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