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 0
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 1407 : signature_context_sort_cb (const void *a,
124 : const void *b)
125 : {
126 1407 : const struct SignatureElement *sa = a;
127 1407 : const struct SignatureElement *sb = b;
128 :
129 1407 : if (sa->group_offset < sb->group_offset)
130 923 : return -1;
131 484 : if (sa->group_offset > sb->group_offset)
132 0 : return 1;
133 484 : if (sa->offset < sb->offset)
134 484 : 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 625 : 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 625 : 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 625 : element = &sig_ctx->elements[sig_ctx->elements_pos++];
173 625 : element->offset = offset;
174 625 : element->group_offset = group_offset;
175 625 : element->master_sig = *master_sig;
176 625 : }
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 710 : 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 710 : GNUNET_JSON_spec_fixed_auto ("master_sig",
417 : &denom_key->master_sig),
418 710 : GNUNET_JSON_spec_timestamp ("stamp_expire_deposit",
419 : &denom_key->expire_deposit),
420 710 : GNUNET_JSON_spec_timestamp ("stamp_expire_withdraw",
421 : &denom_key->withdraw_valid_until),
422 710 : GNUNET_JSON_spec_timestamp ("stamp_start",
423 : &denom_key->valid_from),
424 710 : GNUNET_JSON_spec_timestamp ("stamp_expire_legal",
425 : &denom_key->expire_legal),
426 710 : GNUNET_JSON_spec_mark_optional (
427 : GNUNET_JSON_spec_bool ("lost",
428 : &denom_key->lost),
429 : NULL),
430 710 : TALER_JSON_spec_denom_pub_cipher (NULL,
431 : cipher,
432 : &denom_key->key),
433 710 : GNUNET_JSON_spec_end ()
434 : };
435 :
436 710 : if (GNUNET_OK !=
437 710 : 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 710 : TALER_denom_pub_hash (&denom_key->key,
445 : &denom_key->h_key);
446 710 : if (NULL != sig_ctx)
447 625 : append_signature (sig_ctx,
448 : group_offset,
449 : index,
450 625 : &denom_key->master_sig);
451 710 : if (! check_sigs)
452 85 : return GNUNET_OK;
453 625 : 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 625 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
465 : "Learned denomination key %s\n",
466 : GNUNET_h2s (&denom_key->h_key.hash));
467 625 : 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 9518 : 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 9518 : if (0 !=
689 9518 : TALER_denom_pub_cmp (&denom1->key,
690 : &denom2->key))
691 4875 : return 1;
692 4643 : tmp1 = *denom1;
693 4643 : tmp2 = *denom2;
694 4643 : tmp1.revoked = false;
695 4643 : tmp2.revoked = false;
696 4643 : memset (&tmp1.key,
697 : 0,
698 : sizeof (tmp1.key));
699 4643 : memset (&tmp2.key,
700 : 0,
701 : sizeof (tmp2.key));
702 4643 : 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 *bank_compliance_language = NULL;
933 42 : struct SignatureContext sig_ctx = { 0 };
934 :
935 42 : if (JSON_OBJECT != json_typeof (resp_obj))
936 : {
937 0 : GNUNET_break_op (0);
938 0 : return GNUNET_SYSERR;
939 : }
940 : #if DEBUG
941 : json_dumpf (resp_obj,
942 : stderr,
943 : JSON_INDENT (2));
944 : #endif
945 : /* check the version first */
946 : {
947 : struct TALER_JSON_ProtocolVersion pv;
948 : struct GNUNET_JSON_Specification spec[] = {
949 42 : TALER_JSON_spec_version ("version",
950 : &pv),
951 42 : GNUNET_JSON_spec_end ()
952 : };
953 :
954 42 : if (GNUNET_OK !=
955 42 : GNUNET_JSON_parse (resp_obj,
956 : spec,
957 : NULL, NULL))
958 : {
959 0 : GNUNET_break_op (0);
960 0 : return GNUNET_SYSERR;
961 : }
962 42 : *vc = TALER_EXCHANGE_VC_MATCH;
963 42 : if (EXCHANGE_PROTOCOL_CURRENT < pv.current)
964 : {
965 42 : *vc |= TALER_EXCHANGE_VC_NEWER;
966 42 : if (EXCHANGE_PROTOCOL_CURRENT < pv.current - pv.age)
967 42 : *vc |= TALER_EXCHANGE_VC_INCOMPATIBLE;
968 : }
969 42 : if (EXCHANGE_PROTOCOL_CURRENT > pv.current)
970 : {
971 0 : *vc |= TALER_EXCHANGE_VC_OLDER;
972 0 : if (EXCHANGE_PROTOCOL_CURRENT - EXCHANGE_PROTOCOL_AGE > pv.current)
973 0 : *vc |= TALER_EXCHANGE_VC_INCOMPATIBLE;
974 : }
975 : }
976 :
977 : {
978 : const char *ver;
979 : const char *currency;
980 : const char *asset_type;
981 : struct GNUNET_JSON_Specification mspec[] = {
982 42 : GNUNET_JSON_spec_fixed_auto (
983 : "exchange_sig",
984 : &exchange_sig),
985 42 : GNUNET_JSON_spec_fixed_auto (
986 : "exchange_pub",
987 : &exchange_pub),
988 42 : GNUNET_JSON_spec_fixed_auto (
989 : "master_public_key",
990 : &key_data->master_pub),
991 42 : GNUNET_JSON_spec_array_const ("accounts",
992 : &accounts),
993 42 : GNUNET_JSON_spec_object_const ("wire_fees",
994 : &fees),
995 42 : GNUNET_JSON_spec_array_const ("wads",
996 : &wads),
997 42 : GNUNET_JSON_spec_timestamp (
998 : "list_issue_date",
999 : &key_data->list_issue_date),
1000 42 : GNUNET_JSON_spec_relative_time (
1001 : "reserve_closing_delay",
1002 : &key_data->reserve_closing_delay),
1003 42 : GNUNET_JSON_spec_string (
1004 : "currency",
1005 : ¤cy),
1006 42 : GNUNET_JSON_spec_string (
1007 : "asset_type",
1008 : &asset_type),
1009 42 : GNUNET_JSON_spec_array_const (
1010 : "global_fees",
1011 : &global_fees),
1012 42 : GNUNET_JSON_spec_array_const (
1013 : "signkeys",
1014 : &sign_keys_array),
1015 42 : GNUNET_JSON_spec_array_const (
1016 : "denominations",
1017 : &denominations_by_group),
1018 42 : GNUNET_JSON_spec_mark_optional (
1019 : GNUNET_JSON_spec_array_const (
1020 : "recoup",
1021 : &recoup_array),
1022 : NULL),
1023 42 : GNUNET_JSON_spec_array_const (
1024 : "auditors",
1025 : &auditors_array),
1026 42 : GNUNET_JSON_spec_bool (
1027 : "kyc_enabled",
1028 : &key_data->kyc_enabled),
1029 42 : GNUNET_JSON_spec_mark_optional (
1030 : GNUNET_JSON_spec_object_const ("extensions",
1031 : &manifests),
1032 : &no_extensions),
1033 42 : GNUNET_JSON_spec_mark_optional (
1034 42 : GNUNET_JSON_spec_fixed_auto (
1035 : "extensions_sig",
1036 : &key_data->extensions_sig),
1037 : &no_signature),
1038 42 : GNUNET_JSON_spec_string ("version",
1039 : &ver),
1040 42 : GNUNET_JSON_spec_mark_optional (
1041 : GNUNET_JSON_spec_array_const (
1042 : "wallet_balance_limit_without_kyc",
1043 : &wblwk),
1044 : NULL),
1045 42 : GNUNET_JSON_spec_mark_optional (
1046 : GNUNET_JSON_spec_string ("shopping_url",
1047 : &shopping_url),
1048 : NULL),
1049 42 : GNUNET_JSON_spec_mark_optional (
1050 : GNUNET_JSON_spec_string ("bank_compliance_language",
1051 : &bank_compliance_language),
1052 : NULL),
1053 42 : GNUNET_JSON_spec_mark_optional (
1054 : GNUNET_JSON_spec_bool ("disable_direct_deposit",
1055 : &key_data->disable_direct_deposit),
1056 : NULL),
1057 42 : GNUNET_JSON_spec_end ()
1058 : };
1059 : const char *emsg;
1060 : unsigned int eline;
1061 :
1062 42 : if (GNUNET_OK !=
1063 42 : GNUNET_JSON_parse (resp_obj,
1064 : (check_sig) ? mspec : &mspec[2],
1065 : &emsg,
1066 : &eline))
1067 : {
1068 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1069 : "Parsing /keys failed for `%s' (%u)\n",
1070 : emsg,
1071 : eline);
1072 0 : EXITIF (1);
1073 : }
1074 : {
1075 42 : const json_t *hard_limits = NULL;
1076 42 : const json_t *zero_limits = NULL;
1077 42 : bool no_tiny_amount = false;
1078 : struct GNUNET_JSON_Specification sspec[] = {
1079 42 : TALER_JSON_spec_currency_specification (
1080 : "currency_specification",
1081 : currency,
1082 : &key_data->cspec),
1083 42 : TALER_JSON_spec_amount (
1084 : "stefan_abs",
1085 : currency,
1086 : &key_data->stefan_abs),
1087 42 : TALER_JSON_spec_amount (
1088 : "stefan_log",
1089 : currency,
1090 : &key_data->stefan_log),
1091 42 : GNUNET_JSON_spec_mark_optional (
1092 : TALER_JSON_spec_amount (
1093 : "tiny_amount",
1094 : currency,
1095 : &key_data->tiny_amount),
1096 : &no_tiny_amount),
1097 42 : GNUNET_JSON_spec_mark_optional (
1098 : GNUNET_JSON_spec_array_const (
1099 : "hard_limits",
1100 : &hard_limits),
1101 : NULL),
1102 42 : GNUNET_JSON_spec_mark_optional (
1103 : GNUNET_JSON_spec_array_const (
1104 : "zero_limits",
1105 : &zero_limits),
1106 : NULL),
1107 42 : GNUNET_JSON_spec_double (
1108 : "stefan_lin",
1109 : &key_data->stefan_lin),
1110 42 : GNUNET_JSON_spec_end ()
1111 : };
1112 :
1113 42 : if (GNUNET_OK !=
1114 42 : GNUNET_JSON_parse (resp_obj,
1115 : sspec,
1116 : &emsg,
1117 : &eline))
1118 : {
1119 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1120 : "Parsing /keys failed for `%s' (%u)\n",
1121 : emsg,
1122 : eline);
1123 0 : EXITIF (1);
1124 : }
1125 84 : if ( (NULL != hard_limits) &&
1126 : (GNUNET_OK !=
1127 42 : parse_hard_limits (hard_limits,
1128 : key_data)) )
1129 : {
1130 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1131 : "Parsing hard limits of /keys failed\n");
1132 0 : EXITIF (1);
1133 : }
1134 84 : if ( (NULL != zero_limits) &&
1135 : (GNUNET_OK !=
1136 42 : parse_zero_limits (zero_limits,
1137 : key_data)) )
1138 : {
1139 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1140 : "Parsing hard limits of /keys failed\n");
1141 0 : EXITIF (1);
1142 : }
1143 42 : key_data->tiny_amount_available = ! no_tiny_amount;
1144 : }
1145 :
1146 42 : key_data->currency = GNUNET_strdup (currency);
1147 42 : key_data->version = GNUNET_strdup (ver);
1148 42 : key_data->asset_type = GNUNET_strdup (asset_type);
1149 42 : if (NULL != shopping_url)
1150 0 : key_data->shopping_url = GNUNET_strdup (shopping_url);
1151 42 : if (NULL != bank_compliance_language)
1152 : key_data->bank_compliance_language
1153 0 : = GNUNET_strdup (bank_compliance_language);
1154 42 : if (! no_extensions)
1155 23 : key_data->extensions = json_incref ((json_t *) manifests);
1156 : }
1157 :
1158 : /* parse the global fees */
1159 42 : EXITIF (json_array_size (global_fees) > UINT_MAX);
1160 : key_data->num_global_fees
1161 42 : = (unsigned int) json_array_size (global_fees);
1162 42 : if (0 != key_data->num_global_fees)
1163 : {
1164 : json_t *global_fee;
1165 : size_t index;
1166 :
1167 : key_data->global_fees
1168 42 : = GNUNET_new_array (key_data->num_global_fees,
1169 : struct TALER_EXCHANGE_GlobalFee);
1170 126 : json_array_foreach (global_fees, index, global_fee)
1171 : {
1172 84 : EXITIF (GNUNET_SYSERR ==
1173 : parse_global_fee (&key_data->global_fees[index],
1174 : check_sig,
1175 : global_fee,
1176 : key_data));
1177 : }
1178 : }
1179 :
1180 : /* parse the signing keys */
1181 42 : EXITIF (json_array_size (sign_keys_array) > UINT_MAX);
1182 : key_data->num_sign_keys
1183 42 : = (unsigned int) json_array_size (sign_keys_array);
1184 42 : if (0 != key_data->num_sign_keys)
1185 : {
1186 : json_t *sign_key_obj;
1187 : size_t index;
1188 :
1189 : key_data->sign_keys
1190 42 : = GNUNET_new_array (key_data->num_sign_keys,
1191 : struct TALER_EXCHANGE_SigningPublicKey);
1192 87 : json_array_foreach (sign_keys_array, index, sign_key_obj) {
1193 45 : EXITIF (GNUNET_SYSERR ==
1194 : parse_json_signkey (&key_data->sign_keys[index],
1195 : check_sig,
1196 : sign_key_obj,
1197 : &key_data->master_pub));
1198 : }
1199 : }
1200 :
1201 : /* Parse balance limits */
1202 42 : if (NULL != wblwk)
1203 : {
1204 42 : EXITIF (json_array_size (wblwk) > UINT_MAX);
1205 : key_data->wblwk_length
1206 42 : = (unsigned int) json_array_size (wblwk);
1207 : key_data->wallet_balance_limit_without_kyc
1208 42 : = GNUNET_new_array (key_data->wblwk_length,
1209 : struct TALER_Amount);
1210 43 : for (unsigned int i = 0; i<key_data->wblwk_length; i++)
1211 : {
1212 1 : struct TALER_Amount *a = &key_data->wallet_balance_limit_without_kyc[i];
1213 1 : const json_t *aj = json_array_get (wblwk,
1214 : i);
1215 : struct GNUNET_JSON_Specification spec[] = {
1216 1 : TALER_JSON_spec_amount (NULL,
1217 1 : key_data->currency,
1218 : a),
1219 1 : GNUNET_JSON_spec_end ()
1220 : };
1221 :
1222 1 : EXITIF (GNUNET_OK !=
1223 : GNUNET_JSON_parse (aj,
1224 : spec,
1225 : NULL, NULL));
1226 : }
1227 : }
1228 :
1229 : /* Parse wire accounts */
1230 84 : key_data->fees = parse_fees (&key_data->master_pub,
1231 42 : key_data->currency,
1232 : fees,
1233 : &key_data->fees_len);
1234 42 : EXITIF (NULL == key_data->fees);
1235 : /* parse accounts */
1236 42 : EXITIF (json_array_size (accounts) > UINT_MAX);
1237 42 : GNUNET_array_grow (key_data->accounts,
1238 : key_data->accounts_len,
1239 : json_array_size (accounts));
1240 42 : EXITIF (GNUNET_OK !=
1241 : TALER_EXCHANGE_parse_accounts (&key_data->master_pub,
1242 : accounts,
1243 : key_data->accounts_len,
1244 : key_data->accounts));
1245 :
1246 42 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1247 : "Parsed %u wire accounts from JSON\n",
1248 : key_data->accounts_len);
1249 :
1250 : /* Parse wad partners */
1251 42 : EXITIF (GNUNET_OK !=
1252 : parse_wads (wads,
1253 : check_sig,
1254 : key_data));
1255 :
1256 :
1257 : /* Parse the supported extension(s): age-restriction. */
1258 : /* FIXME[Oec]: maybe lift all this into a FP in TALER_Extension ? */
1259 42 : if (! no_extensions)
1260 : {
1261 23 : if (no_signature)
1262 : {
1263 23 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1264 : "found extensions without signature\n");
1265 : }
1266 : else
1267 : {
1268 : /* We have an extensions object. Verify its signature. */
1269 0 : EXITIF (GNUNET_OK !=
1270 : TALER_extensions_verify_manifests_signature (
1271 : manifests,
1272 : &key_data->extensions_sig,
1273 : &key_data->master_pub));
1274 :
1275 : /* Parse and set the the configuration of the extensions accordingly */
1276 0 : EXITIF (GNUNET_OK !=
1277 : TALER_extensions_load_manifests (manifests));
1278 : }
1279 :
1280 : /* Assuming we might have now a new value for age_mask, set it in key_data */
1281 23 : key_data->age_mask = TALER_extensions_get_age_restriction_mask ();
1282 : }
1283 :
1284 : /*
1285 : * Parse the denomination keys, merging with the
1286 : * possibly EXISTING array as required (/keys cherry picking).
1287 : *
1288 : * The denominations are grouped by common values of
1289 : * {cipher, value, fee, age_mask}.
1290 : */
1291 : {
1292 : json_t *group_obj;
1293 : unsigned int group_idx;
1294 :
1295 291 : json_array_foreach (denominations_by_group,
1296 : group_idx,
1297 : group_obj)
1298 : {
1299 : /* First, parse { cipher, fees, value, age_mask, hash } of the current
1300 : group. */
1301 249 : struct TALER_DenominationGroup group = {0};
1302 : const json_t *denom_keys_array;
1303 : struct GNUNET_JSON_Specification group_spec[] = {
1304 249 : TALER_JSON_spec_denomination_group (NULL,
1305 249 : key_data->currency,
1306 : &group),
1307 249 : GNUNET_JSON_spec_array_const ("denoms",
1308 : &denom_keys_array),
1309 249 : GNUNET_JSON_spec_end ()
1310 : };
1311 : json_t *denom_key_obj;
1312 : unsigned int index;
1313 :
1314 249 : EXITIF (GNUNET_SYSERR ==
1315 : GNUNET_JSON_parse (group_obj,
1316 : group_spec,
1317 : NULL,
1318 : NULL));
1319 :
1320 : /* Now, parse the individual denominations */
1321 959 : json_array_foreach (denom_keys_array,
1322 : index,
1323 : denom_key_obj)
1324 : {
1325 : /* Set the common fields from the group for this particular
1326 : denomination. Required to make the validity check inside
1327 : parse_json_denomkey_partially pass */
1328 710 : struct TALER_EXCHANGE_DenomPublicKey dk = {
1329 : .value = group.value,
1330 : .fees = group.fees,
1331 : .key.age_mask = group.age_mask
1332 : };
1333 710 : bool found = false;
1334 :
1335 710 : EXITIF (GNUNET_SYSERR ==
1336 : parse_json_denomkey_partially (&dk,
1337 : group.cipher,
1338 : check_sig,
1339 : denom_key_obj,
1340 : &key_data->master_pub,
1341 : group_idx,
1342 : index,
1343 : check_sig
1344 : ? &sig_ctx
1345 : : NULL));
1346 710 : for (unsigned int j = 0;
1347 10202 : j<key_data->num_denom_keys;
1348 9492 : j++)
1349 : {
1350 9518 : if (0 == denoms_cmp (&dk,
1351 9518 : &key_data->denom_keys[j]))
1352 : {
1353 26 : found = true;
1354 26 : break;
1355 : }
1356 : }
1357 :
1358 710 : if (found)
1359 : {
1360 : /* 0:0:0 did not support /keys cherry picking */
1361 26 : TALER_LOG_DEBUG ("Skipping denomination key: already know it\n");
1362 26 : TALER_denom_pub_free (&dk.key);
1363 26 : continue;
1364 : }
1365 :
1366 684 : if (key_data->denom_keys_size == key_data->num_denom_keys)
1367 110 : GNUNET_array_grow (key_data->denom_keys,
1368 : key_data->denom_keys_size,
1369 : key_data->denom_keys_size * 2 + 2);
1370 684 : GNUNET_assert (key_data->denom_keys_size >
1371 : key_data->num_denom_keys);
1372 684 : GNUNET_assert (key_data->num_denom_keys < UINT_MAX);
1373 684 : key_data->denom_keys[key_data->num_denom_keys++] = dk;
1374 :
1375 : /* Update "last_denom_issue_date" */
1376 684 : TALER_LOG_DEBUG ("Adding denomination key that is valid_until %s\n",
1377 : GNUNET_TIME_timestamp2s (dk.valid_from));
1378 : key_data->last_denom_issue_date
1379 684 : = GNUNET_TIME_timestamp_max (key_data->last_denom_issue_date,
1380 : dk.valid_from);
1381 : }; /* end of json_array_foreach over denominations */
1382 : } /* end of json_array_foreach over groups of denominations */
1383 : } /* end of scope for group_ojb/group_idx */
1384 :
1385 : /* parse the auditor information */
1386 : {
1387 : json_t *auditor_info;
1388 : unsigned int index;
1389 :
1390 : /* Merge with the existing auditor information we have (/keys cherry picking) */
1391 54 : json_array_foreach (auditors_array, index, auditor_info)
1392 : {
1393 : struct TALER_EXCHANGE_AuditorInformation ai;
1394 12 : bool found = false;
1395 :
1396 12 : memset (&ai,
1397 : 0,
1398 : sizeof (ai));
1399 12 : EXITIF (GNUNET_SYSERR ==
1400 : parse_json_auditor (&ai,
1401 : check_sig,
1402 : auditor_info,
1403 : key_data));
1404 12 : for (unsigned int j = 0; j<key_data->num_auditors; j++)
1405 : {
1406 0 : struct TALER_EXCHANGE_AuditorInformation *aix = &key_data->auditors[j];
1407 :
1408 0 : if (0 == GNUNET_memcmp (&ai.auditor_pub,
1409 : &aix->auditor_pub))
1410 : {
1411 0 : found = true;
1412 : /* Merge denomination key signatures of downloaded /keys into existing
1413 : auditor information 'aix'. */
1414 0 : TALER_LOG_DEBUG (
1415 : "Merging %u new audited keys with %u known audited keys\n",
1416 : aix->num_denom_keys,
1417 : ai.num_denom_keys);
1418 0 : for (unsigned int i = 0; i<ai.num_denom_keys; i++)
1419 : {
1420 0 : bool kfound = false;
1421 :
1422 0 : for (unsigned int k = 0; k<aix->num_denom_keys; k++)
1423 : {
1424 0 : if (aix->denom_keys[k].denom_key_offset ==
1425 0 : ai.denom_keys[i].denom_key_offset)
1426 : {
1427 0 : kfound = true;
1428 0 : break;
1429 : }
1430 : }
1431 0 : if (! kfound)
1432 0 : GNUNET_array_append (aix->denom_keys,
1433 : aix->num_denom_keys,
1434 : ai.denom_keys[i]);
1435 : }
1436 0 : break;
1437 : }
1438 : }
1439 12 : if (found)
1440 : {
1441 0 : GNUNET_array_grow (ai.denom_keys,
1442 : ai.num_denom_keys,
1443 : 0);
1444 0 : GNUNET_free (ai.auditor_url);
1445 0 : GNUNET_free (ai.auditor_name);
1446 0 : continue; /* we are done */
1447 : }
1448 12 : if (key_data->auditors_size == key_data->num_auditors)
1449 12 : GNUNET_array_grow (key_data->auditors,
1450 : key_data->auditors_size,
1451 : key_data->auditors_size * 2 + 2);
1452 12 : GNUNET_assert (key_data->auditors_size >
1453 : key_data->num_auditors);
1454 12 : GNUNET_assert (NULL != ai.auditor_url);
1455 12 : GNUNET_assert (key_data->num_auditors < UINT_MAX);
1456 12 : key_data->auditors[key_data->num_auditors++] = ai;
1457 : };
1458 : }
1459 :
1460 : /* parse the revocation/recoup information */
1461 42 : if (NULL != recoup_array)
1462 : {
1463 : json_t *recoup_info;
1464 : unsigned int index;
1465 :
1466 42 : json_array_foreach (recoup_array, index, recoup_info)
1467 : {
1468 : struct TALER_DenominationHashP h_denom_pub;
1469 : struct GNUNET_JSON_Specification spec[] = {
1470 0 : GNUNET_JSON_spec_fixed_auto ("h_denom_pub",
1471 : &h_denom_pub),
1472 0 : GNUNET_JSON_spec_end ()
1473 : };
1474 :
1475 0 : EXITIF (GNUNET_OK !=
1476 : GNUNET_JSON_parse (recoup_info,
1477 : spec,
1478 : NULL, NULL));
1479 0 : for (unsigned int j = 0;
1480 0 : j<key_data->num_denom_keys;
1481 0 : j++)
1482 : {
1483 0 : if (0 == GNUNET_memcmp (&h_denom_pub,
1484 : &key_data->denom_keys[j].h_key))
1485 : {
1486 0 : key_data->denom_keys[j].revoked = true;
1487 0 : break;
1488 : }
1489 : }
1490 : }
1491 : }
1492 :
1493 42 : if (check_sig)
1494 : {
1495 : struct GNUNET_HashContext *hash_context;
1496 : struct GNUNET_HashCode hc;
1497 :
1498 34 : hash_context = GNUNET_CRYPTO_hash_context_start ();
1499 34 : qsort (sig_ctx.elements,
1500 34 : sig_ctx.elements_pos,
1501 : sizeof (struct SignatureElement),
1502 : &signature_context_sort_cb);
1503 659 : for (unsigned int i = 0; i<sig_ctx.elements_pos; i++)
1504 : {
1505 625 : struct SignatureElement *element = &sig_ctx.elements[i];
1506 :
1507 625 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1508 : "Adding %u,%u,%s\n",
1509 : element->group_offset,
1510 : element->offset,
1511 : TALER_B2S (&element->master_sig));
1512 625 : GNUNET_CRYPTO_hash_context_read (hash_context,
1513 625 : &element->master_sig,
1514 : sizeof (element->master_sig));
1515 : }
1516 34 : GNUNET_array_grow (sig_ctx.elements,
1517 : sig_ctx.elements_size,
1518 : 0);
1519 34 : GNUNET_CRYPTO_hash_context_finish (hash_context,
1520 : &hc);
1521 34 : EXITIF (GNUNET_OK !=
1522 : TALER_EXCHANGE_test_signing_key (key_data,
1523 : &exchange_pub));
1524 34 : EXITIF (GNUNET_OK !=
1525 : TALER_exchange_online_key_set_verify (
1526 : key_data->list_issue_date,
1527 : &hc,
1528 : &exchange_pub,
1529 : &exchange_sig));
1530 : }
1531 42 : return GNUNET_OK;
1532 :
1533 0 : EXITIF_exit:
1534 0 : *vc = TALER_EXCHANGE_VC_PROTOCOL_ERROR;
1535 0 : return GNUNET_SYSERR;
1536 : }
1537 :
1538 :
1539 : enum GNUNET_GenericReturnValue
1540 185 : TALER_EXCHANGE_test_signing_key (
1541 : const struct TALER_EXCHANGE_Keys *keys,
1542 : const struct TALER_ExchangePublicKeyP *pub)
1543 : {
1544 : struct GNUNET_TIME_Absolute now;
1545 :
1546 : /* we will check using a tolerance of 1h for the time */
1547 185 : now = GNUNET_TIME_absolute_get ();
1548 194 : for (unsigned int i = 0; i<keys->num_sign_keys; i++)
1549 194 : if ( (GNUNET_TIME_absolute_cmp (
1550 : keys->sign_keys[i].valid_from.abs_time,
1551 : <=,
1552 : GNUNET_TIME_absolute_add (now,
1553 185 : LIFETIME_TOLERANCE))) &&
1554 185 : (GNUNET_TIME_absolute_cmp (
1555 : keys->sign_keys[i].valid_until.abs_time,
1556 : >,
1557 : GNUNET_TIME_absolute_subtract (now,
1558 185 : LIFETIME_TOLERANCE))) &&
1559 185 : (0 == GNUNET_memcmp (pub,
1560 : &keys->sign_keys[i].key)) )
1561 185 : return GNUNET_OK;
1562 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1563 : "Signing key not valid at time %s\n",
1564 : GNUNET_TIME_absolute2s (now));
1565 0 : return GNUNET_SYSERR;
1566 : }
1567 :
1568 :
1569 : const struct TALER_EXCHANGE_DenomPublicKey *
1570 30 : TALER_EXCHANGE_get_denomination_key (
1571 : const struct TALER_EXCHANGE_Keys *keys,
1572 : const struct TALER_DenominationPublicKey *pk)
1573 : {
1574 105 : for (unsigned int i = 0; i<keys->num_denom_keys; i++)
1575 105 : if (0 ==
1576 105 : TALER_denom_pub_cmp (pk,
1577 105 : &keys->denom_keys[i].key))
1578 30 : return &keys->denom_keys[i];
1579 0 : return NULL;
1580 : }
1581 :
1582 :
1583 : const struct TALER_EXCHANGE_GlobalFee *
1584 13 : TALER_EXCHANGE_get_global_fee (
1585 : const struct TALER_EXCHANGE_Keys *keys,
1586 : struct GNUNET_TIME_Timestamp ts)
1587 : {
1588 13 : for (unsigned int i = 0; i<keys->num_global_fees; i++)
1589 : {
1590 13 : const struct TALER_EXCHANGE_GlobalFee *gf = &keys->global_fees[i];
1591 :
1592 13 : if (GNUNET_TIME_timestamp_cmp (ts,
1593 : >=,
1594 13 : gf->start_date) &&
1595 13 : GNUNET_TIME_timestamp_cmp (ts,
1596 : <,
1597 : gf->end_date))
1598 13 : return gf;
1599 : }
1600 0 : return NULL;
1601 : }
1602 :
1603 :
1604 : struct TALER_EXCHANGE_DenomPublicKey *
1605 72 : TALER_EXCHANGE_copy_denomination_key (
1606 : const struct TALER_EXCHANGE_DenomPublicKey *key)
1607 : {
1608 : struct TALER_EXCHANGE_DenomPublicKey *copy;
1609 :
1610 72 : copy = GNUNET_new (struct TALER_EXCHANGE_DenomPublicKey);
1611 72 : *copy = *key;
1612 72 : TALER_denom_pub_copy (©->key,
1613 : &key->key);
1614 72 : return copy;
1615 : }
1616 :
1617 :
1618 : void
1619 72 : TALER_EXCHANGE_destroy_denomination_key (
1620 : struct TALER_EXCHANGE_DenomPublicKey *key)
1621 : {
1622 72 : TALER_denom_pub_free (&key->key);
1623 72 : GNUNET_free (key);
1624 72 : }
1625 :
1626 :
1627 : const struct TALER_EXCHANGE_DenomPublicKey *
1628 113 : TALER_EXCHANGE_get_denomination_key_by_hash (
1629 : const struct TALER_EXCHANGE_Keys *keys,
1630 : const struct TALER_DenominationHashP *hc)
1631 : {
1632 : /* FIXME-optimization: should we maybe use a hash map here? */
1633 2049 : for (unsigned int i = 0; i<keys->num_denom_keys; i++)
1634 2049 : if (0 == GNUNET_memcmp (hc,
1635 : &keys->denom_keys[i].h_key))
1636 113 : return &keys->denom_keys[i];
1637 0 : return NULL;
1638 : }
1639 :
1640 :
1641 : struct TALER_EXCHANGE_Keys *
1642 377 : TALER_EXCHANGE_keys_incref (struct TALER_EXCHANGE_Keys *keys)
1643 : {
1644 377 : GNUNET_assert (keys->rc < UINT_MAX);
1645 377 : keys->rc++;
1646 377 : return keys;
1647 : }
1648 :
1649 :
1650 : void
1651 473 : TALER_EXCHANGE_keys_decref (struct TALER_EXCHANGE_Keys *keys)
1652 : {
1653 473 : if (NULL == keys)
1654 54 : return;
1655 419 : GNUNET_assert (0 < keys->rc);
1656 419 : keys->rc--;
1657 419 : if (0 != keys->rc)
1658 377 : return;
1659 42 : GNUNET_array_grow (keys->sign_keys,
1660 : keys->num_sign_keys,
1661 : 0);
1662 811 : for (unsigned int i = 0; i<keys->num_denom_keys; i++)
1663 769 : TALER_denom_pub_free (&keys->denom_keys[i].key);
1664 42 : keys->num_denom_keys = 0;
1665 42 : GNUNET_array_grow (keys->denom_keys,
1666 : keys->denom_keys_size,
1667 : 0);
1668 56 : for (unsigned int i = 0; i<keys->num_auditors; i++)
1669 : {
1670 14 : GNUNET_array_grow (keys->auditors[i].denom_keys,
1671 : keys->auditors[i].num_denom_keys,
1672 : 0);
1673 14 : GNUNET_free (keys->auditors[i].auditor_url);
1674 14 : GNUNET_free (keys->auditors[i].auditor_name);
1675 : }
1676 42 : GNUNET_array_grow (keys->auditors,
1677 : keys->auditors_size,
1678 : 0);
1679 42 : TALER_EXCHANGE_free_accounts (keys->accounts_len,
1680 : keys->accounts);
1681 42 : GNUNET_array_grow (keys->accounts,
1682 : keys->accounts_len,
1683 : 0);
1684 42 : free_fees (keys->fees,
1685 : keys->fees_len);
1686 42 : GNUNET_array_grow (keys->hard_limits,
1687 : keys->hard_limits_length,
1688 : 0);
1689 42 : GNUNET_array_grow (keys->zero_limits,
1690 : keys->zero_limits_length,
1691 : 0);
1692 42 : json_decref (keys->extensions);
1693 42 : GNUNET_free (keys->cspec.name);
1694 42 : json_decref (keys->cspec.map_alt_unit_names);
1695 42 : GNUNET_array_grow (keys->cspec.common_amounts,
1696 : keys->cspec.num_common_amounts,
1697 : 0);
1698 42 : GNUNET_free (keys->wallet_balance_limit_without_kyc);
1699 42 : GNUNET_free (keys->version);
1700 42 : GNUNET_free (keys->currency);
1701 42 : GNUNET_free (keys->asset_type);
1702 42 : GNUNET_free (keys->shopping_url);
1703 42 : GNUNET_free (keys->bank_compliance_language);
1704 42 : for (unsigned int i = 0; i < keys->num_wad_partners; i++)
1705 0 : GNUNET_free (keys->wad_partners[i].partner_base_url);
1706 42 : GNUNET_free (keys->wad_partners);
1707 42 : GNUNET_free (keys->global_fees);
1708 42 : GNUNET_free (keys->exchange_url);
1709 42 : GNUNET_free (keys);
1710 : }
1711 :
1712 :
1713 : struct TALER_EXCHANGE_Keys *
1714 8 : TALER_EXCHANGE_keys_from_json (const json_t *j)
1715 : {
1716 : const json_t *jkeys;
1717 : const char *url;
1718 : uint32_t version;
1719 8 : struct GNUNET_TIME_Timestamp expire
1720 : = GNUNET_TIME_UNIT_ZERO_TS;
1721 : struct GNUNET_JSON_Specification spec[] = {
1722 8 : GNUNET_JSON_spec_uint32 ("version",
1723 : &version),
1724 8 : GNUNET_JSON_spec_object_const ("keys",
1725 : &jkeys),
1726 8 : TALER_JSON_spec_web_url ("exchange_url",
1727 : &url),
1728 8 : GNUNET_JSON_spec_mark_optional (
1729 : GNUNET_JSON_spec_timestamp ("expire",
1730 : &expire),
1731 : NULL),
1732 8 : GNUNET_JSON_spec_end ()
1733 : };
1734 : struct TALER_EXCHANGE_Keys *keys;
1735 : enum TALER_EXCHANGE_VersionCompatibility compat;
1736 :
1737 8 : if (NULL == j)
1738 0 : return NULL;
1739 8 : if (GNUNET_OK !=
1740 8 : GNUNET_JSON_parse (j,
1741 : spec,
1742 : NULL, NULL))
1743 : {
1744 0 : GNUNET_break_op (0);
1745 0 : return NULL;
1746 : }
1747 8 : if (0 != version)
1748 : {
1749 0 : return NULL; /* unsupported version */
1750 : }
1751 8 : keys = GNUNET_new (struct TALER_EXCHANGE_Keys);
1752 8 : if (GNUNET_OK !=
1753 8 : TALER_EXCHANGE_decode_keys_json_ (jkeys,
1754 : false,
1755 : keys,
1756 : &compat))
1757 : {
1758 0 : GNUNET_break (0);
1759 0 : return NULL;
1760 : }
1761 8 : keys->rc = 1;
1762 8 : keys->key_data_expiration = expire;
1763 8 : keys->exchange_url = GNUNET_strdup (url);
1764 8 : return keys;
1765 : }
1766 :
1767 :
1768 : /**
1769 : * Data we track per denomination group.
1770 : */
1771 : struct GroupData
1772 : {
1773 : /**
1774 : * The json blob with the group meta-data and list of denominations
1775 : */
1776 : json_t *json;
1777 :
1778 : /**
1779 : * Meta data for this group.
1780 : */
1781 : struct TALER_DenominationGroup meta;
1782 : };
1783 :
1784 :
1785 : /**
1786 : * Add denomination group represented by @a value
1787 : * to list of denominations in @a cls. Also frees
1788 : * the @a value.
1789 : *
1790 : * @param[in,out] cls a `json_t *` with an array to build
1791 : * @param key unused
1792 : * @param value a `struct GroupData *`
1793 : * @return #GNUNET_OK (continue to iterate)
1794 : */
1795 : static enum GNUNET_GenericReturnValue
1796 26 : add_grp (void *cls,
1797 : const struct GNUNET_HashCode *key,
1798 : void *value)
1799 : {
1800 26 : json_t *denominations_by_group = cls;
1801 26 : struct GroupData *gd = value;
1802 : const char *cipher;
1803 : json_t *ge;
1804 26 : bool age_restricted = gd->meta.age_mask.bits != 0;
1805 :
1806 : (void) key;
1807 26 : switch (gd->meta.cipher)
1808 : {
1809 13 : case GNUNET_CRYPTO_BSA_RSA:
1810 13 : cipher = age_restricted ? "RSA+age_restricted" : "RSA";
1811 13 : break;
1812 13 : case GNUNET_CRYPTO_BSA_CS:
1813 13 : cipher = age_restricted ? "CS+age_restricted" : "CS";
1814 13 : break;
1815 0 : default:
1816 0 : GNUNET_assert (false);
1817 : }
1818 :
1819 26 : ge = GNUNET_JSON_PACK (
1820 : GNUNET_JSON_pack_string ("cipher",
1821 : cipher),
1822 : GNUNET_JSON_pack_array_steal ("denoms",
1823 : gd->json),
1824 : TALER_JSON_PACK_DENOM_FEES ("fee",
1825 : &gd->meta.fees),
1826 : GNUNET_JSON_pack_allow_null (
1827 : age_restricted
1828 : ? GNUNET_JSON_pack_uint64 ("age_mask",
1829 : gd->meta.age_mask.bits)
1830 : : GNUNET_JSON_pack_string ("dummy",
1831 : NULL)),
1832 : TALER_JSON_pack_amount ("value",
1833 : &gd->meta.value));
1834 26 : GNUNET_assert (0 ==
1835 : json_array_append_new (denominations_by_group,
1836 : ge));
1837 26 : GNUNET_free (gd);
1838 26 : return GNUNET_OK;
1839 : }
1840 :
1841 :
1842 : /**
1843 : * Convert array of account restrictions @a ars to JSON.
1844 : *
1845 : * @param ar_len length of @a ars
1846 : * @param ars account restrictions to convert
1847 : * @return JSON representation
1848 : */
1849 : static json_t *
1850 16 : ar_to_json (unsigned int ar_len,
1851 : const struct TALER_EXCHANGE_AccountRestriction ars[static ar_len])
1852 16 : {
1853 : json_t *rval;
1854 :
1855 16 : rval = json_array ();
1856 16 : GNUNET_assert (NULL != rval);
1857 16 : for (unsigned int i = 0; i<ar_len; i++)
1858 : {
1859 0 : const struct TALER_EXCHANGE_AccountRestriction *ar = &ars[i];
1860 :
1861 0 : switch (ar->type)
1862 : {
1863 0 : case TALER_EXCHANGE_AR_INVALID:
1864 0 : GNUNET_break (0);
1865 0 : json_decref (rval);
1866 0 : return NULL;
1867 0 : case TALER_EXCHANGE_AR_DENY:
1868 0 : GNUNET_assert (
1869 : 0 ==
1870 : json_array_append_new (
1871 : rval,
1872 : GNUNET_JSON_PACK (
1873 : GNUNET_JSON_pack_string ("type",
1874 : "deny"))));
1875 0 : break;
1876 0 : case TALER_EXCHANGE_AR_REGEX:
1877 0 : GNUNET_assert (
1878 : 0 ==
1879 : json_array_append_new (
1880 : rval,
1881 : GNUNET_JSON_PACK (
1882 : GNUNET_JSON_pack_string (
1883 : "type",
1884 : "regex"),
1885 : GNUNET_JSON_pack_string (
1886 : "payto_regex",
1887 : ar->details.regex.posix_egrep),
1888 : GNUNET_JSON_pack_string (
1889 : "human_hint",
1890 : ar->details.regex.human_hint),
1891 : GNUNET_JSON_pack_object_incref (
1892 : "human_hint_i18n",
1893 : (json_t *) ar->details.regex.human_hint_i18n)
1894 : )));
1895 0 : break;
1896 : }
1897 : }
1898 16 : return rval;
1899 : }
1900 :
1901 :
1902 : json_t *
1903 8 : TALER_EXCHANGE_keys_to_json (const struct TALER_EXCHANGE_Keys *kd)
1904 : {
1905 : struct GNUNET_TIME_Timestamp now;
1906 : json_t *keys;
1907 : json_t *signkeys;
1908 : json_t *denominations_by_group;
1909 : json_t *auditors;
1910 : json_t *recoup;
1911 : json_t *wire_fees;
1912 : json_t *accounts;
1913 : json_t *global_fees;
1914 8 : json_t *wblwk = NULL;
1915 : json_t *wads_json;
1916 : json_t *hard_limits;
1917 : json_t *zero_limits;
1918 :
1919 8 : now = GNUNET_TIME_timestamp_get ();
1920 8 : signkeys = json_array ();
1921 8 : GNUNET_assert (NULL != signkeys);
1922 16 : for (unsigned int i = 0; i<kd->num_sign_keys; i++)
1923 : {
1924 8 : const struct TALER_EXCHANGE_SigningPublicKey *sk = &kd->sign_keys[i];
1925 : json_t *signkey;
1926 :
1927 8 : if (GNUNET_TIME_timestamp_cmp (now,
1928 : >,
1929 : sk->valid_until))
1930 0 : continue; /* skip keys that have expired */
1931 8 : signkey = GNUNET_JSON_PACK (
1932 : GNUNET_JSON_pack_data_auto ("key",
1933 : &sk->key),
1934 : GNUNET_JSON_pack_data_auto ("master_sig",
1935 : &sk->master_sig),
1936 : GNUNET_JSON_pack_timestamp ("stamp_start",
1937 : sk->valid_from),
1938 : GNUNET_JSON_pack_timestamp ("stamp_expire",
1939 : sk->valid_until),
1940 : GNUNET_JSON_pack_timestamp ("stamp_end",
1941 : sk->valid_legal));
1942 8 : GNUNET_assert (NULL != signkey);
1943 8 : GNUNET_assert (0 ==
1944 : json_array_append_new (signkeys,
1945 : signkey));
1946 : }
1947 :
1948 8 : denominations_by_group = json_array ();
1949 8 : GNUNET_assert (NULL != denominations_by_group);
1950 : {
1951 : struct GNUNET_CONTAINER_MultiHashMap *dbg;
1952 :
1953 8 : dbg = GNUNET_CONTAINER_multihashmap_create (128,
1954 : false);
1955 93 : for (unsigned int i = 0; i<kd->num_denom_keys; i++)
1956 : {
1957 85 : const struct TALER_EXCHANGE_DenomPublicKey *dk = &kd->denom_keys[i];
1958 85 : struct TALER_DenominationGroup meta = {
1959 85 : .cipher = dk->key.bsign_pub_key->cipher,
1960 : .value = dk->value,
1961 : .fees = dk->fees,
1962 : .age_mask = dk->key.age_mask
1963 : };
1964 : struct GNUNET_HashCode key;
1965 : struct GroupData *gd;
1966 : json_t *denom;
1967 : struct GNUNET_JSON_PackSpec key_spec;
1968 :
1969 85 : if (GNUNET_TIME_timestamp_cmp (now,
1970 : >,
1971 : dk->expire_deposit))
1972 0 : continue; /* skip keys that have expired */
1973 85 : TALER_denomination_group_get_key (&meta,
1974 : &key);
1975 85 : gd = GNUNET_CONTAINER_multihashmap_get (dbg,
1976 : &key);
1977 85 : if (NULL == gd)
1978 : {
1979 26 : gd = GNUNET_new (struct GroupData);
1980 26 : gd->meta = meta;
1981 26 : gd->json = json_array ();
1982 26 : GNUNET_assert (NULL != gd->json);
1983 26 : GNUNET_assert (
1984 : GNUNET_OK ==
1985 : GNUNET_CONTAINER_multihashmap_put (dbg,
1986 : &key,
1987 : gd,
1988 : GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1989 :
1990 : }
1991 85 : switch (meta.cipher)
1992 : {
1993 42 : case GNUNET_CRYPTO_BSA_RSA:
1994 : key_spec =
1995 42 : GNUNET_JSON_pack_rsa_public_key (
1996 : "rsa_pub",
1997 42 : dk->key.bsign_pub_key->details.rsa_public_key);
1998 42 : break;
1999 43 : case GNUNET_CRYPTO_BSA_CS:
2000 : key_spec =
2001 43 : GNUNET_JSON_pack_data_varsize (
2002 : "cs_pub",
2003 43 : &dk->key.bsign_pub_key->details.cs_public_key,
2004 : sizeof (dk->key.bsign_pub_key->details.cs_public_key));
2005 43 : break;
2006 0 : default:
2007 0 : GNUNET_assert (false);
2008 : }
2009 85 : denom = GNUNET_JSON_PACK (
2010 : GNUNET_JSON_pack_timestamp ("stamp_expire_deposit",
2011 : dk->expire_deposit),
2012 : GNUNET_JSON_pack_timestamp ("stamp_expire_withdraw",
2013 : dk->withdraw_valid_until),
2014 : GNUNET_JSON_pack_timestamp ("stamp_start",
2015 : dk->valid_from),
2016 : GNUNET_JSON_pack_timestamp ("stamp_expire_legal",
2017 : dk->expire_legal),
2018 : GNUNET_JSON_pack_data_auto ("master_sig",
2019 : &dk->master_sig),
2020 : key_spec
2021 : );
2022 85 : GNUNET_assert (0 ==
2023 : json_array_append_new (gd->json,
2024 : denom));
2025 : }
2026 8 : GNUNET_CONTAINER_multihashmap_iterate (dbg,
2027 : &add_grp,
2028 : denominations_by_group);
2029 8 : GNUNET_CONTAINER_multihashmap_destroy (dbg);
2030 : }
2031 :
2032 8 : auditors = json_array ();
2033 8 : GNUNET_assert (NULL != auditors);
2034 10 : for (unsigned int i = 0; i<kd->num_auditors; i++)
2035 : {
2036 2 : const struct TALER_EXCHANGE_AuditorInformation *ai = &kd->auditors[i];
2037 : json_t *a;
2038 : json_t *adenoms;
2039 :
2040 2 : adenoms = json_array ();
2041 2 : GNUNET_assert (NULL != adenoms);
2042 2 : for (unsigned int j = 0; j<ai->num_denom_keys; j++)
2043 : {
2044 0 : const struct TALER_EXCHANGE_AuditorDenominationInfo *adi =
2045 0 : &ai->denom_keys[j];
2046 0 : const struct TALER_EXCHANGE_DenomPublicKey *dk =
2047 0 : &kd->denom_keys[adi->denom_key_offset];
2048 : json_t *k;
2049 :
2050 0 : GNUNET_assert (adi->denom_key_offset < kd->num_denom_keys);
2051 0 : if (GNUNET_TIME_timestamp_cmp (now,
2052 : >,
2053 : dk->expire_deposit))
2054 0 : continue; /* skip auditor signatures for denomination keys that have expired */
2055 0 : GNUNET_assert (adi->denom_key_offset < kd->num_denom_keys);
2056 0 : k = GNUNET_JSON_PACK (
2057 : GNUNET_JSON_pack_data_auto ("denom_pub_h",
2058 : &dk->h_key),
2059 : GNUNET_JSON_pack_data_auto ("auditor_sig",
2060 : &adi->auditor_sig));
2061 0 : GNUNET_assert (0 ==
2062 : json_array_append_new (adenoms,
2063 : k));
2064 : }
2065 :
2066 2 : a = GNUNET_JSON_PACK (
2067 : GNUNET_JSON_pack_data_auto ("auditor_pub",
2068 : &ai->auditor_pub),
2069 : GNUNET_JSON_pack_string ("auditor_url",
2070 : ai->auditor_url),
2071 : GNUNET_JSON_pack_string ("auditor_name",
2072 : ai->auditor_name),
2073 : GNUNET_JSON_pack_array_steal ("denomination_keys",
2074 : adenoms));
2075 2 : GNUNET_assert (0 ==
2076 : json_array_append_new (auditors,
2077 : a));
2078 : }
2079 :
2080 8 : global_fees = json_array ();
2081 8 : GNUNET_assert (NULL != global_fees);
2082 24 : for (unsigned int i = 0; i<kd->num_global_fees; i++)
2083 : {
2084 16 : const struct TALER_EXCHANGE_GlobalFee *gf
2085 16 : = &kd->global_fees[i];
2086 :
2087 16 : if (GNUNET_TIME_absolute_is_past (gf->end_date.abs_time))
2088 0 : continue;
2089 16 : GNUNET_assert (
2090 : 0 ==
2091 : json_array_append_new (
2092 : global_fees,
2093 : GNUNET_JSON_PACK (
2094 : GNUNET_JSON_pack_timestamp ("start_date",
2095 : gf->start_date),
2096 : GNUNET_JSON_pack_timestamp ("end_date",
2097 : gf->end_date),
2098 : TALER_JSON_PACK_GLOBAL_FEES (&gf->fees),
2099 : GNUNET_JSON_pack_time_rel ("history_expiration",
2100 : gf->history_expiration),
2101 : GNUNET_JSON_pack_time_rel ("purse_timeout",
2102 : gf->purse_timeout),
2103 : GNUNET_JSON_pack_uint64 ("purse_account_limit",
2104 : gf->purse_account_limit),
2105 : GNUNET_JSON_pack_data_auto ("master_sig",
2106 : &gf->master_sig))));
2107 : }
2108 :
2109 8 : accounts = json_array ();
2110 8 : GNUNET_assert (NULL != accounts);
2111 16 : for (unsigned int i = 0; i<kd->accounts_len; i++)
2112 : {
2113 8 : const struct TALER_EXCHANGE_WireAccount *acc
2114 8 : = &kd->accounts[i];
2115 : json_t *credit_restrictions;
2116 : json_t *debit_restrictions;
2117 :
2118 : credit_restrictions
2119 8 : = ar_to_json (acc->credit_restrictions_length,
2120 8 : acc->credit_restrictions);
2121 8 : GNUNET_assert (NULL != credit_restrictions);
2122 : debit_restrictions
2123 8 : = ar_to_json (acc->debit_restrictions_length,
2124 8 : acc->debit_restrictions);
2125 8 : GNUNET_assert (NULL != debit_restrictions);
2126 8 : GNUNET_assert (
2127 : 0 ==
2128 : json_array_append_new (
2129 : accounts,
2130 : GNUNET_JSON_PACK (
2131 : TALER_JSON_pack_full_payto ("payto_uri",
2132 : acc->fpayto_uri),
2133 : GNUNET_JSON_pack_allow_null (
2134 : GNUNET_JSON_pack_string ("conversion_url",
2135 : acc->conversion_url)),
2136 : GNUNET_JSON_pack_allow_null (
2137 : GNUNET_JSON_pack_string ("open_banking_gateway",
2138 : acc->open_banking_gateway)),
2139 : GNUNET_JSON_pack_allow_null (
2140 : GNUNET_JSON_pack_string ("wire_transfer_gateway",
2141 : acc->wire_transfer_gateway)),
2142 : GNUNET_JSON_pack_int64 ("priority",
2143 : acc->priority),
2144 : GNUNET_JSON_pack_allow_null (
2145 : GNUNET_JSON_pack_string ("bank_label",
2146 : acc->bank_label)),
2147 : GNUNET_JSON_pack_array_steal ("debit_restrictions",
2148 : debit_restrictions),
2149 : GNUNET_JSON_pack_array_steal ("credit_restrictions",
2150 : credit_restrictions),
2151 : GNUNET_JSON_pack_data_auto ("master_sig",
2152 : &acc->master_sig))));
2153 : }
2154 8 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2155 : "Serialized %u/%u wire accounts to JSON\n",
2156 : (unsigned int) json_array_size (accounts),
2157 : kd->accounts_len);
2158 :
2159 8 : wire_fees = json_object ();
2160 8 : GNUNET_assert (NULL != wire_fees);
2161 16 : for (unsigned int i = 0; i<kd->fees_len; i++)
2162 : {
2163 8 : const struct TALER_EXCHANGE_WireFeesByMethod *fbw
2164 8 : = &kd->fees[i];
2165 : json_t *wf;
2166 :
2167 8 : wf = json_array ();
2168 8 : GNUNET_assert (NULL != wf);
2169 8 : for (struct TALER_EXCHANGE_WireAggregateFees *p = fbw->fees_head;
2170 24 : NULL != p;
2171 16 : p = p->next)
2172 : {
2173 16 : GNUNET_assert (
2174 : 0 ==
2175 : json_array_append_new (
2176 : wf,
2177 : GNUNET_JSON_PACK (
2178 : TALER_JSON_pack_amount ("wire_fee",
2179 : &p->fees.wire),
2180 : TALER_JSON_pack_amount ("closing_fee",
2181 : &p->fees.closing),
2182 : GNUNET_JSON_pack_timestamp ("start_date",
2183 : p->start_date),
2184 : GNUNET_JSON_pack_timestamp ("end_date",
2185 : p->end_date),
2186 : GNUNET_JSON_pack_data_auto ("sig",
2187 : &p->master_sig))));
2188 : }
2189 8 : GNUNET_assert (0 ==
2190 : json_object_set_new (wire_fees,
2191 : fbw->method,
2192 : wf));
2193 : }
2194 :
2195 8 : recoup = json_array ();
2196 8 : GNUNET_assert (NULL != recoup);
2197 93 : for (unsigned int i = 0; i<kd->num_denom_keys; i++)
2198 : {
2199 85 : const struct TALER_EXCHANGE_DenomPublicKey *dk
2200 85 : = &kd->denom_keys[i];
2201 85 : if (! dk->revoked)
2202 85 : continue;
2203 0 : GNUNET_assert (0 ==
2204 : json_array_append_new (
2205 : recoup,
2206 : GNUNET_JSON_PACK (
2207 : GNUNET_JSON_pack_data_auto ("h_denom_pub",
2208 : &dk->h_key))));
2209 : }
2210 :
2211 8 : wblwk = json_array ();
2212 8 : GNUNET_assert (NULL != wblwk);
2213 8 : for (unsigned int i = 0; i<kd->wblwk_length; i++)
2214 : {
2215 0 : const struct TALER_Amount *a = &kd->wallet_balance_limit_without_kyc[i];
2216 :
2217 0 : GNUNET_assert (0 ==
2218 : json_array_append_new (
2219 : wblwk,
2220 : TALER_JSON_from_amount (a)));
2221 : }
2222 :
2223 8 : hard_limits = json_array ();
2224 8 : for (unsigned int i = 0; i < kd->hard_limits_length; i++)
2225 : {
2226 0 : const struct TALER_EXCHANGE_AccountLimit *al
2227 0 : = &kd->hard_limits[i];
2228 : json_t *j;
2229 :
2230 0 : j = GNUNET_JSON_PACK (
2231 : TALER_JSON_pack_amount ("threshold",
2232 : &al->threshold),
2233 : GNUNET_JSON_pack_time_rel ("timeframe",
2234 : al->timeframe),
2235 : TALER_JSON_pack_kycte ("operation_type",
2236 : al->operation_type),
2237 : GNUNET_JSON_pack_bool ("soft_limit",
2238 : al->soft_limit)
2239 : );
2240 0 : GNUNET_assert (0 ==
2241 : json_array_append_new (
2242 : hard_limits,
2243 : j));
2244 : }
2245 :
2246 8 : zero_limits = json_array ();
2247 10 : for (unsigned int i = 0; i < kd->zero_limits_length; i++)
2248 : {
2249 2 : const struct TALER_EXCHANGE_ZeroLimitedOperation *zol
2250 2 : = &kd->zero_limits[i];
2251 : json_t *j;
2252 :
2253 2 : j = GNUNET_JSON_PACK (
2254 : TALER_JSON_pack_kycte ("operation_type",
2255 : zol->operation_type)
2256 : );
2257 2 : GNUNET_assert (0 ==
2258 : json_array_append_new (
2259 : zero_limits,
2260 : j));
2261 : }
2262 :
2263 8 : wads_json = json_array ();
2264 8 : GNUNET_assert (NULL != wads_json);
2265 8 : for (unsigned int i = 0; i < kd->num_wad_partners; i++)
2266 : {
2267 0 : const struct TALER_EXCHANGE_WadPartner *wp
2268 0 : = &kd->wad_partners[i];
2269 :
2270 0 : GNUNET_assert (
2271 : 0 ==
2272 : json_array_append_new (
2273 : wads_json,
2274 : GNUNET_JSON_PACK (
2275 : GNUNET_JSON_pack_string ("partner_base_url",
2276 : wp->partner_base_url),
2277 : GNUNET_JSON_pack_data_auto ("partner_master_pub",
2278 : &wp->partner_master_pub),
2279 : TALER_JSON_pack_amount ("wad_fee",
2280 : &wp->wad_fee),
2281 : GNUNET_JSON_pack_time_rel ("wad_frequency",
2282 : wp->wad_frequency),
2283 : GNUNET_JSON_pack_timestamp ("start_date",
2284 : wp->start_date),
2285 : GNUNET_JSON_pack_timestamp ("end_date",
2286 : wp->end_date),
2287 : GNUNET_JSON_pack_data_auto ("master_sig",
2288 : &wp->master_sig))));
2289 : }
2290 :
2291 8 : keys = GNUNET_JSON_PACK (
2292 : GNUNET_JSON_pack_string ("version",
2293 : kd->version),
2294 : GNUNET_JSON_pack_string ("currency",
2295 : kd->currency),
2296 : GNUNET_JSON_pack_object_steal ("currency_specification",
2297 : TALER_JSON_currency_specs_to_json (
2298 : &kd->cspec)),
2299 : TALER_JSON_pack_amount ("stefan_abs",
2300 : &kd->stefan_abs),
2301 : TALER_JSON_pack_amount ("stefan_log",
2302 : &kd->stefan_log),
2303 : GNUNET_JSON_pack_double ("stefan_lin",
2304 : kd->stefan_lin),
2305 : GNUNET_JSON_pack_allow_null (
2306 : kd->tiny_amount_available
2307 : ? TALER_JSON_pack_amount ("tiny_amount",
2308 : &kd->tiny_amount)
2309 : : GNUNET_JSON_pack_string ("dummy",
2310 : NULL)),
2311 : GNUNET_JSON_pack_string ("asset_type",
2312 : kd->asset_type),
2313 : GNUNET_JSON_pack_allow_null (
2314 : GNUNET_JSON_pack_string ("shopping_url",
2315 : kd->shopping_url)),
2316 : GNUNET_JSON_pack_allow_null (
2317 : GNUNET_JSON_pack_string ("bank_compliance_language",
2318 : kd->bank_compliance_language)),
2319 : GNUNET_JSON_pack_bool ("disable_direct_deposit",
2320 : kd->disable_direct_deposit),
2321 : GNUNET_JSON_pack_data_auto ("master_public_key",
2322 : &kd->master_pub),
2323 : GNUNET_JSON_pack_time_rel ("reserve_closing_delay",
2324 : kd->reserve_closing_delay),
2325 : GNUNET_JSON_pack_timestamp ("list_issue_date",
2326 : kd->list_issue_date),
2327 : GNUNET_JSON_pack_array_steal ("global_fees",
2328 : global_fees),
2329 : GNUNET_JSON_pack_array_steal ("signkeys",
2330 : signkeys),
2331 : GNUNET_JSON_pack_object_steal ("wire_fees",
2332 : wire_fees),
2333 : GNUNET_JSON_pack_array_steal ("accounts",
2334 : accounts),
2335 : GNUNET_JSON_pack_array_steal ("wads",
2336 : wads_json),
2337 : GNUNET_JSON_pack_array_steal ("hard_limits",
2338 : hard_limits),
2339 : GNUNET_JSON_pack_array_steal ("zero_limits",
2340 : zero_limits),
2341 : GNUNET_JSON_pack_array_steal ("denominations",
2342 : denominations_by_group),
2343 : GNUNET_JSON_pack_allow_null (
2344 : GNUNET_JSON_pack_array_steal ("recoup",
2345 : recoup)),
2346 : GNUNET_JSON_pack_array_steal ("auditors",
2347 : auditors),
2348 : GNUNET_JSON_pack_bool ("kyc_enabled",
2349 : kd->kyc_enabled),
2350 : GNUNET_JSON_pack_allow_null (
2351 : GNUNET_JSON_pack_object_incref ("extensions",
2352 : kd->extensions)),
2353 : GNUNET_JSON_pack_allow_null (
2354 : GNUNET_is_zero (&kd->extensions_sig)
2355 : ? GNUNET_JSON_pack_string ("dummy",
2356 : NULL)
2357 : : GNUNET_JSON_pack_data_auto ("extensions_sig",
2358 : &kd->extensions_sig)),
2359 : GNUNET_JSON_pack_allow_null (
2360 : GNUNET_JSON_pack_array_steal ("wallet_balance_limit_without_kyc",
2361 : wblwk))
2362 :
2363 : );
2364 8 : return GNUNET_JSON_PACK (
2365 : GNUNET_JSON_pack_uint64 ("version",
2366 : EXCHANGE_SERIALIZATION_FORMAT_VERSION),
2367 : GNUNET_JSON_pack_allow_null (
2368 : GNUNET_JSON_pack_timestamp ("expire",
2369 : kd->key_data_expiration)),
2370 : GNUNET_JSON_pack_string ("exchange_url",
2371 : kd->exchange_url),
2372 : GNUNET_JSON_pack_object_steal ("keys",
2373 : keys));
2374 : }
2375 :
2376 :
2377 : /* end of exchange_api_handle.c */
|