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