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