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