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