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