taler-exchange-httpd_keys.c (134823B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2020-2025 Taler Systems SA 4 5 TALER is free software; you can redistribute it and/or modify it under the 6 terms of the GNU Affero General Public License as published by the Free Software 7 Foundation; either version 3, or (at your option) any later version. 8 9 TALER is distributed in the hope that it will be useful, but WITHOUT ANY 10 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 11 A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. 12 13 You should have received a copy of the GNU Affero General Public License along with 14 TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> 15 */ 16 /** 17 * @file taler-exchange-httpd_keys.c 18 * @brief management of our various keys 19 * @author Christian Grothoff 20 * @author Özgür Kesim 21 */ 22 #include "taler/platform.h" 23 #include "taler/taler_json_lib.h" 24 #include "taler/taler_mhd_lib.h" 25 #include "taler/taler_kyclogic_lib.h" 26 #include "taler/taler_dbevents.h" 27 #include "taler-exchange-httpd.h" 28 #include "taler-exchange-httpd_config.h" 29 #include "taler-exchange-httpd_keys.h" 30 #include "taler-exchange-httpd_responses.h" 31 #include "taler/taler_exchangedb_plugin.h" 32 #include "taler/taler_extensions.h" 33 34 35 /** 36 * How many /keys request do we hold in suspension at 37 * most at any time? 38 */ 39 #define SKR_LIMIT 32 40 41 42 /** 43 * When do we forcefully timeout a /keys request? 44 * Matches the 120s hard-coded into exchange_api_handle.c 45 */ 46 #define KEYS_TIMEOUT \ 47 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 2) 48 49 50 /** 51 * Information about a denomination on offer by the denomination helper. 52 */ 53 struct HelperDenomination 54 { 55 56 /** 57 * When will the helper start to use this key for signing? 58 */ 59 struct GNUNET_TIME_Timestamp start_time; 60 61 /** 62 * For how long will the helper allow signing? 0 if 63 * the key was revoked or purged. 64 */ 65 struct GNUNET_TIME_Relative validity_duration; 66 67 /** 68 * Hash of the full denomination key. 69 */ 70 struct TALER_DenominationHashP h_denom_pub; 71 72 /** 73 * Signature over this key from the security module's key. 74 */ 75 struct TALER_SecurityModuleSignatureP sm_sig; 76 77 /** 78 * The (full) public key. 79 */ 80 struct TALER_DenominationPublicKey denom_pub; 81 82 /** 83 * Details depend on the @e denom_pub.cipher type. 84 */ 85 union 86 { 87 88 /** 89 * Hash of the RSA key. 90 */ 91 struct TALER_RsaPubHashP h_rsa; 92 93 /** 94 * Hash of the CS key. 95 */ 96 struct TALER_CsPubHashP h_cs; 97 98 } h_details; 99 100 /** 101 * Name in configuration section for this denomination type. 102 */ 103 char *section_name; 104 105 106 }; 107 108 109 /** 110 * Signatures of an auditor over a denomination key of this exchange. 111 */ 112 struct TEH_AuditorSignature 113 { 114 /** 115 * We store the signatures in a DLL. 116 */ 117 struct TEH_AuditorSignature *prev; 118 119 /** 120 * We store the signatures in a DLL. 121 */ 122 struct TEH_AuditorSignature *next; 123 124 /** 125 * A signature from the auditor. 126 */ 127 struct TALER_AuditorSignatureP asig; 128 129 /** 130 * Public key of the auditor. 131 */ 132 struct TALER_AuditorPublicKeyP apub; 133 134 }; 135 136 137 /** 138 * Information about a signing key on offer by the esign helper. 139 */ 140 struct HelperSignkey 141 { 142 /** 143 * When will the helper start to use this key for signing? 144 */ 145 struct GNUNET_TIME_Timestamp start_time; 146 147 /** 148 * For how long will the helper allow signing? 0 if 149 * the key was revoked or purged. 150 */ 151 struct GNUNET_TIME_Relative validity_duration; 152 153 /** 154 * The public key. 155 */ 156 struct TALER_ExchangePublicKeyP exchange_pub; 157 158 /** 159 * Signature over this key from the security module's key. 160 */ 161 struct TALER_SecurityModuleSignatureP sm_sig; 162 163 }; 164 165 166 /** 167 * State associated with the crypto helpers / security modules. NOT updated 168 * when the #key_generation is updated (instead constantly kept in sync 169 * whenever #TEH_keys_get_state() is called). 170 */ 171 struct HelperState 172 { 173 174 /** 175 * Handle for the esign/EdDSA helper. 176 */ 177 struct TALER_CRYPTO_ExchangeSignHelper *esh; 178 179 /** 180 * Handle for the denom/RSA helper. 181 */ 182 struct TALER_CRYPTO_RsaDenominationHelper *rsadh; 183 184 /** 185 * Handle for the denom/CS helper. 186 */ 187 struct TALER_CRYPTO_CsDenominationHelper *csdh; 188 189 /** 190 * Map from H(denom_pub) to `struct HelperDenomination` entries. 191 */ 192 struct GNUNET_CONTAINER_MultiHashMap *denom_keys; 193 194 /** 195 * Map from H(rsa_pub) to `struct HelperDenomination` entries. 196 */ 197 struct GNUNET_CONTAINER_MultiHashMap *rsa_keys; 198 199 /** 200 * Map from H(cs_pub) to `struct HelperDenomination` entries. 201 */ 202 struct GNUNET_CONTAINER_MultiHashMap *cs_keys; 203 204 /** 205 * Map from `struct TALER_ExchangePublicKey` to `struct HelperSignkey` 206 * entries. Based on the fact that a `struct GNUNET_PeerIdentity` is also 207 * an EdDSA public key. 208 */ 209 struct GNUNET_CONTAINER_MultiPeerMap *esign_keys; 210 211 }; 212 213 214 /** 215 * Information we track for the crypto helpers. Preserved 216 * when the @e key_generation changes, thus kept separate. 217 */ 218 static struct HelperState helpers; 219 220 221 /** 222 * Entry in (sorted) array with possible pre-build responses for /keys. 223 * We keep pre-build responses for the various (valid) cherry-picking 224 * values around. 225 */ 226 struct KeysResponseData 227 { 228 229 /** 230 * Response to return if the client supports (deflate) compression. 231 */ 232 struct MHD_Response *response_compressed; 233 234 /** 235 * Response to return if the client does not support compression. 236 */ 237 struct MHD_Response *response_uncompressed; 238 239 /** 240 * ETag for these responses. 241 */ 242 char *etag; 243 244 /** 245 * Cherry-picking timestamp the client must have set for this 246 * response to be valid. 0 if this is the "full" response. 247 * The client's request must include this date or a higher one 248 * for this response to be applicable. 249 */ 250 struct GNUNET_TIME_Timestamp cherry_pick_date; 251 252 }; 253 254 255 /** 256 * @brief All information about an exchange online signing key (which is used to 257 * sign messages from the exchange). 258 */ 259 struct SigningKey 260 { 261 262 /** 263 * The exchange's (online signing) public key. 264 */ 265 struct TALER_ExchangePublicKeyP exchange_pub; 266 267 /** 268 * Meta data about the signing key, such as validity periods. 269 */ 270 struct TALER_EXCHANGEDB_SignkeyMetaData meta; 271 272 /** 273 * The long-term offline master key's signature for this signing key. 274 * Signs over @e exchange_pub and @e meta. 275 */ 276 struct TALER_MasterSignatureP master_sig; 277 278 }; 279 280 struct TEH_KeyStateHandle 281 { 282 283 /** 284 * Mapping from denomination keys to denomination key issue struct. 285 * Used to lookup the key by hash. 286 */ 287 struct GNUNET_CONTAINER_MultiHashMap *denomkey_map; 288 289 /** 290 * Mapping from serial ID's to denomination key issue struct. 291 * Used to lookup the key by serial ID. 292 * 293 * FIXME: We need a 64-bit version of this in GNUNET. 294 */ 295 struct GNUNET_CONTAINER_MultiHashMap32 *denomserial_map; 296 297 /** 298 * Map from `struct TALER_ExchangePublicKey` to `struct SigningKey` 299 * entries. Based on the fact that a `struct GNUNET_PeerIdentity` is also 300 * an EdDSA public key. 301 */ 302 struct GNUNET_CONTAINER_MultiPeerMap *signkey_map; 303 304 /** 305 * Head of DLL of our global fees. 306 */ 307 struct TEH_GlobalFee *gf_head; 308 309 /** 310 * Tail of DLL of our global fees. 311 */ 312 struct TEH_GlobalFee *gf_tail; 313 314 /** 315 * json array with the auditors of this exchange. Contains exactly 316 * the information needed for the "auditors" field of the /keys response. 317 */ 318 json_t *auditors; 319 320 /** 321 * json array with the global fees of this exchange. Contains exactly 322 * the information needed for the "global_fees" field of the /keys response. 323 */ 324 json_t *global_fees; 325 326 /** 327 * Sorted array of responses to /keys (MUST be sorted by cherry-picking date) of 328 * length @e krd_array_length; 329 */ 330 struct KeysResponseData *krd_array; 331 332 /** 333 * Length of the @e krd_array. 334 */ 335 unsigned int krd_array_length; 336 337 /** 338 * Cached reply for a GET /management/keys request. Used so we do not 339 * re-create the reply every time. 340 */ 341 json_t *management_keys_reply; 342 343 /** 344 * For which (global) key_generation was this data structure created? 345 * Used to check when we are outdated and need to be re-generated. 346 */ 347 uint64_t key_generation; 348 349 /** 350 * When did we initiate the key reloading? 351 */ 352 struct GNUNET_TIME_Timestamp reload_time; 353 354 /** 355 * What is the period at which we rotate keys 356 * (signing or denomination keys)? 357 */ 358 struct GNUNET_TIME_Relative rekey_frequency; 359 360 /** 361 * When does our online signing key expire and we 362 * thus need to re-generate this response? 363 */ 364 struct GNUNET_TIME_Timestamp signature_expires; 365 366 /** 367 * True if #finish_keys_response() was not yet run and this key state 368 * is only suitable for the /management/keys API. 369 */ 370 bool management_only; 371 372 }; 373 374 375 /** 376 * Entry of /keys requests that are currently suspended because we are 377 * waiting for /keys to become ready. 378 */ 379 struct SuspendedKeysRequests 380 { 381 /** 382 * Kept in a DLL. 383 */ 384 struct SuspendedKeysRequests *next; 385 386 /** 387 * Kept in a DLL. 388 */ 389 struct SuspendedKeysRequests *prev; 390 391 /** 392 * The suspended connection. 393 */ 394 struct MHD_Connection *connection; 395 396 /** 397 * When does this request timeout? 398 */ 399 struct GNUNET_TIME_Absolute timeout; 400 }; 401 402 403 /** 404 * Information we track about wire fees. 405 */ 406 struct WireFeeSet 407 { 408 409 /** 410 * Kept in a DLL. 411 */ 412 struct WireFeeSet *next; 413 414 /** 415 * Kept in a DLL. 416 */ 417 struct WireFeeSet *prev; 418 419 /** 420 * Actual fees. 421 */ 422 struct TALER_WireFeeSet fees; 423 424 /** 425 * Start date of fee validity (inclusive). 426 */ 427 struct GNUNET_TIME_Timestamp start_date; 428 429 /** 430 * End date of fee validity (exclusive). 431 */ 432 struct GNUNET_TIME_Timestamp end_date; 433 434 /** 435 * Wire method the fees apply to. 436 */ 437 char *method; 438 }; 439 440 441 /** 442 * State we keep per thread to cache the wire part of the /keys response. 443 */ 444 struct WireStateHandle 445 { 446 447 /** 448 * JSON reply for wire response. 449 */ 450 json_t *json_reply; 451 452 /** 453 * ETag for this response (if any). 454 */ 455 char *etag; 456 457 /** 458 * head of DLL of wire fees. 459 */ 460 struct WireFeeSet *wfs_head; 461 462 /** 463 * Tail of DLL of wire fees. 464 */ 465 struct WireFeeSet *wfs_tail; 466 467 /** 468 * Earliest timestamp of all the wire methods when we have no more fees. 469 */ 470 struct GNUNET_TIME_Absolute cache_expiration; 471 472 /** 473 * @e cache_expiration time, formatted. 474 */ 475 char dat[128]; 476 477 /** 478 * For which (global) wire_generation was this data structure created? 479 * Used to check when we are outdated and need to be re-generated. 480 */ 481 uint64_t wire_generation; 482 483 /** 484 * Is the wire data ready? 485 */ 486 bool ready; 487 488 }; 489 490 491 /** 492 * Stores the latest generation of our wire response. 493 */ 494 static struct WireStateHandle *wire_state; 495 496 /** 497 * Handler listening for wire updates by other exchange 498 * services. 499 */ 500 static struct GNUNET_DB_EventHandler *wire_eh; 501 502 /** 503 * Counter incremented whenever we have a reason to re-build the #wire_state 504 * because something external changed. 505 */ 506 static uint64_t wire_generation; 507 508 509 /** 510 * Stores the latest generation of our key state. 511 */ 512 static struct TEH_KeyStateHandle *key_state; 513 514 /** 515 * Counter incremented whenever we have a reason to re-build the keys because 516 * something external changed. See #TEH_keys_get_state() and 517 * #TEH_keys_update_states() for uses of this variable. 518 */ 519 static uint64_t key_generation; 520 521 /** 522 * Handler listening for wire updates by other exchange 523 * services. 524 */ 525 static struct GNUNET_DB_EventHandler *keys_eh; 526 527 /** 528 * Head of DLL of suspended /keys requests. 529 */ 530 static struct SuspendedKeysRequests *skr_head; 531 532 /** 533 * Tail of DLL of suspended /keys requests. 534 */ 535 static struct SuspendedKeysRequests *skr_tail; 536 537 /** 538 * Number of entries in the @e skr_head DLL. 539 */ 540 static unsigned int skr_size; 541 542 /** 543 * Task to force timeouts on /keys requests. 544 */ 545 static struct GNUNET_SCHEDULER_Task *keys_tt; 546 547 /** 548 * For how long should a signing key be legally retained? 549 * Configuration value. 550 */ 551 static struct GNUNET_TIME_Relative signkey_legal_duration; 552 553 /** 554 * What type of asset are we dealing with here? 555 */ 556 static char *asset_type; 557 558 /** 559 * RSA security module public key, all zero if not known. 560 */ 561 static struct TALER_SecurityModulePublicKeyP denom_rsa_sm_pub; 562 563 /** 564 * CS security module public key, all zero if not known. 565 */ 566 static struct TALER_SecurityModulePublicKeyP denom_cs_sm_pub; 567 568 /** 569 * EdDSA security module public key, all zero if not known. 570 */ 571 static struct TALER_SecurityModulePublicKeyP esign_sm_pub; 572 573 /** 574 * Are we shutting down? 575 */ 576 static bool terminating; 577 578 579 /** 580 * Free memory associated with @a wsh 581 * 582 * @param[in] wsh wire state to destroy 583 */ 584 static void 585 destroy_wire_state (struct WireStateHandle *wsh) 586 { 587 struct WireFeeSet *wfs; 588 589 while (NULL != (wfs = wsh->wfs_head)) 590 { 591 GNUNET_CONTAINER_DLL_remove (wsh->wfs_head, 592 wsh->wfs_tail, 593 wfs); 594 GNUNET_free (wfs->method); 595 GNUNET_free (wfs); 596 } 597 json_decref (wsh->json_reply); 598 GNUNET_free (wsh->etag); 599 GNUNET_free (wsh); 600 } 601 602 603 /** 604 * Function called whenever another exchange process has updated 605 * the wire data in the database. 606 * 607 * @param cls NULL 608 * @param extra unused 609 * @param extra_size number of bytes in @a extra unused 610 */ 611 static void 612 wire_update_event_cb (void *cls, 613 const void *extra, 614 size_t extra_size) 615 { 616 (void) cls; 617 (void) extra; 618 (void) extra_size; 619 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 620 "Received wire update event\n"); 621 TEH_check_invariants (); 622 wire_generation++; 623 key_generation++; 624 TEH_resume_keys_requests (false); 625 } 626 627 628 /** 629 * Add information about a wire account to @a cls. 630 * 631 * @param cls a `json_t *` array to expand with wire account details 632 * @param payto_uri the exchange bank account URI to add 633 * @param conversion_url URL of a conversion service, NULL if there is no conversion 634 * @param open_banking_gateway URL of an open banking gateway, NULL if there is none 635 * @param wire_transfer_gateway URL of a wire transfer gateway, NULL if there is none 636 * @param debit_restrictions JSON array with debit restrictions on the account 637 * @param credit_restrictions JSON array with credit restrictions on the account 638 * @param master_sig master key signature affirming that this is a bank 639 * account of the exchange (of purpose #TALER_SIGNATURE_MASTER_WIRE_DETAILS) 640 * @param bank_label label the wallet should use to display the account, can be NULL 641 * @param priority priority for ordering bank account labels 642 */ 643 static void 644 add_wire_account ( 645 void *cls, 646 const struct TALER_FullPayto payto_uri, 647 const char *conversion_url, 648 const char *open_banking_gateway, 649 const char *wire_transfer_gateway, 650 const json_t *debit_restrictions, 651 const json_t *credit_restrictions, 652 const struct TALER_MasterSignatureP *master_sig, 653 const char *bank_label, 654 int64_t priority) 655 { 656 json_t *a = cls; 657 658 if (GNUNET_OK != 659 TALER_exchange_wire_signature_check ( 660 payto_uri, 661 conversion_url, 662 open_banking_gateway, 663 wire_transfer_gateway, 664 debit_restrictions, 665 credit_restrictions, 666 &TEH_master_public_key, 667 master_sig)) 668 { 669 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 670 "Database has wire account with invalid signature. Skipping entry. Did the exchange offline public key change?\n"); 671 return; 672 } 673 if (0 != 674 json_array_append_new ( 675 a, 676 GNUNET_JSON_PACK ( 677 TALER_JSON_pack_full_payto ( 678 "payto_uri", 679 payto_uri), 680 GNUNET_JSON_pack_allow_null ( 681 GNUNET_JSON_pack_string ( 682 "conversion_url", 683 conversion_url)), 684 GNUNET_JSON_pack_allow_null ( 685 GNUNET_JSON_pack_string ( 686 "open_banking_gateway", 687 open_banking_gateway)), 688 GNUNET_JSON_pack_allow_null ( 689 GNUNET_JSON_pack_string ( 690 "wire_transfer_gateway", 691 wire_transfer_gateway)), 692 GNUNET_JSON_pack_allow_null ( 693 GNUNET_JSON_pack_string ( 694 "bank_label", 695 bank_label)), 696 GNUNET_JSON_pack_int64 ( 697 "priority", 698 priority), 699 GNUNET_JSON_pack_array_incref ( 700 "debit_restrictions", 701 (json_t *) debit_restrictions), 702 GNUNET_JSON_pack_array_incref ( 703 "credit_restrictions", 704 (json_t *) credit_restrictions), 705 GNUNET_JSON_pack_data_auto ( 706 "master_sig", 707 master_sig)))) 708 { 709 GNUNET_break (0); /* out of memory!? */ 710 return; 711 } 712 } 713 714 715 /** 716 * Closure for #add_wire_fee(). 717 */ 718 struct AddContext 719 { 720 /** 721 * Wire method the fees are for. 722 */ 723 char *wire_method; 724 725 /** 726 * Wire state we are building. 727 */ 728 struct WireStateHandle *wsh; 729 730 /** 731 * Array to append the fee to. 732 */ 733 json_t *a; 734 735 /** 736 * Set to the maximum end-date seen. 737 */ 738 struct GNUNET_TIME_Absolute max_seen; 739 }; 740 741 742 /** 743 * Add information about a wire account to @a cls. 744 * 745 * @param cls a `struct AddContext` 746 * @param fees the wire fees we charge 747 * @param start_date from when are these fees valid (start date) 748 * @param end_date until when are these fees valid (end date, exclusive) 749 * @param master_sig master key signature affirming that this is the correct 750 * fee (of purpose #TALER_SIGNATURE_MASTER_WIRE_FEES) 751 */ 752 static void 753 add_wire_fee (void *cls, 754 const struct TALER_WireFeeSet *fees, 755 struct GNUNET_TIME_Timestamp start_date, 756 struct GNUNET_TIME_Timestamp end_date, 757 const struct TALER_MasterSignatureP *master_sig) 758 { 759 struct AddContext *ac = cls; 760 struct WireFeeSet *wfs; 761 762 if (GNUNET_OK != 763 TALER_exchange_offline_wire_fee_verify ( 764 ac->wire_method, 765 start_date, 766 end_date, 767 fees, 768 &TEH_master_public_key, 769 master_sig)) 770 { 771 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 772 "Database has wire fee with invalid signature. Skipping entry. Did the exchange offline public key change?\n"); 773 return; 774 } 775 ac->max_seen = GNUNET_TIME_absolute_max (ac->max_seen, 776 end_date.abs_time); 777 wfs = GNUNET_new (struct WireFeeSet); 778 wfs->start_date = start_date; 779 wfs->end_date = end_date; 780 wfs->fees = *fees; 781 wfs->method = GNUNET_strdup (ac->wire_method); 782 GNUNET_CONTAINER_DLL_insert (ac->wsh->wfs_head, 783 ac->wsh->wfs_tail, 784 wfs); 785 if (0 != 786 json_array_append_new ( 787 ac->a, 788 GNUNET_JSON_PACK ( 789 TALER_JSON_pack_amount ("wire_fee", 790 &fees->wire), 791 TALER_JSON_pack_amount ("closing_fee", 792 &fees->closing), 793 GNUNET_JSON_pack_timestamp ("start_date", 794 start_date), 795 GNUNET_JSON_pack_timestamp ("end_date", 796 end_date), 797 GNUNET_JSON_pack_data_auto ("sig", 798 master_sig)))) 799 { 800 GNUNET_break (0); /* out of memory!? */ 801 return; 802 } 803 } 804 805 806 /** 807 * Create the wire response from our database state. 808 * 809 * @return NULL on error 810 */ 811 static struct WireStateHandle * 812 build_wire_state (void) 813 { 814 json_t *wire_accounts_array; 815 json_t *wire_fee_object; 816 uint64_t wg = wire_generation; /* must be obtained FIRST */ 817 enum GNUNET_DB_QueryStatus qs; 818 struct WireStateHandle *wsh; 819 json_t *wads; 820 821 wsh = GNUNET_new (struct WireStateHandle); 822 wsh->wire_generation = wg; 823 wire_accounts_array = json_array (); 824 GNUNET_assert (NULL != wire_accounts_array); 825 qs = TEH_plugin->get_wire_accounts (TEH_plugin->cls, 826 &add_wire_account, 827 wire_accounts_array); 828 if (0 > qs) 829 { 830 GNUNET_break (0); 831 json_decref (wire_accounts_array); 832 wsh->ready = false; 833 return wsh; 834 } 835 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 836 "Built wire data with %u accounts (%d)\n", 837 (unsigned int) json_array_size (wire_accounts_array), 838 (int) qs); 839 wire_fee_object = json_object (); 840 GNUNET_assert (NULL != wire_fee_object); 841 wsh->cache_expiration = GNUNET_TIME_UNIT_FOREVER_ABS; 842 { 843 json_t *account; 844 size_t index; 845 846 json_array_foreach (wire_accounts_array, 847 index, 848 account) 849 { 850 char *wire_method; 851 const char *payto_uri = json_string_value (json_object_get (account, 852 "payto_uri")); 853 854 GNUNET_assert (NULL != payto_uri); 855 wire_method = TALER_payto_get_method (payto_uri); 856 if (NULL == wire_method) 857 { 858 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 859 "No wire method in `%s'\n", 860 payto_uri); 861 wsh->ready = false; 862 json_decref (wire_accounts_array); 863 json_decref (wire_fee_object); 864 return wsh; 865 } 866 if (NULL == json_object_get (wire_fee_object, 867 wire_method)) 868 { 869 struct AddContext ac = { 870 .wire_method = wire_method, 871 .wsh = wsh, 872 .a = json_array () 873 }; 874 875 GNUNET_assert (NULL != ac.a); 876 qs = TEH_plugin->get_wire_fees (TEH_plugin->cls, 877 wire_method, 878 &add_wire_fee, 879 &ac); 880 if (0 > qs) 881 { 882 GNUNET_break (0); 883 json_decref (ac.a); 884 json_decref (wire_fee_object); 885 json_decref (wire_accounts_array); 886 GNUNET_free (wire_method); 887 wsh->ready = false; 888 return wsh; 889 } 890 if (0 != json_array_size (ac.a)) 891 { 892 wsh->cache_expiration 893 = GNUNET_TIME_absolute_min (ac.max_seen, 894 wsh->cache_expiration); 895 GNUNET_assert (0 == 896 json_object_set_new (wire_fee_object, 897 wire_method, 898 ac.a)); 899 } 900 else 901 { 902 json_decref (ac.a); 903 } 904 } 905 GNUNET_free (wire_method); 906 } 907 } 908 909 wads = json_array (); /* #7271 */ 910 GNUNET_assert (NULL != wads); 911 wsh->json_reply = GNUNET_JSON_PACK ( 912 GNUNET_JSON_pack_array_steal ("accounts", 913 wire_accounts_array), 914 GNUNET_JSON_pack_array_steal ("wads", 915 wads), 916 GNUNET_JSON_pack_object_steal ("fees", 917 wire_fee_object)); 918 wsh->ready = true; 919 return wsh; 920 } 921 922 923 void 924 TEH_wire_update_state (void) 925 { 926 struct GNUNET_DB_EventHeaderP es = { 927 .size = htons (sizeof (es)), 928 .type = htons (TALER_DBEVENT_EXCHANGE_WIRE_UPDATED), 929 }; 930 931 TEH_plugin->event_notify (TEH_plugin->cls, 932 &es, 933 NULL, 934 0); 935 wire_generation++; 936 key_generation++; 937 } 938 939 940 /** 941 * Return the current key state for this thread. Possibly 942 * re-builds the key state if we have reason to believe 943 * that something changed. 944 * 945 * @return NULL on error 946 */ 947 static struct WireStateHandle * 948 get_wire_state (void) 949 { 950 struct WireStateHandle *old_wsh; 951 952 old_wsh = wire_state; 953 if ( (NULL == old_wsh) || 954 (old_wsh->wire_generation < wire_generation) ) 955 { 956 struct WireStateHandle *wsh; 957 958 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 959 "Rebuilding wire, generation upgrade from %llu to %llu\n", 960 (unsigned long long) (NULL == old_wsh) ? 0LL : 961 old_wsh->wire_generation, 962 (unsigned long long) wire_generation); 963 TEH_check_invariants (); 964 wsh = build_wire_state (); 965 wire_state = wsh; 966 if (NULL != old_wsh) 967 destroy_wire_state (old_wsh); 968 TEH_check_invariants (); 969 return wsh; 970 } 971 return old_wsh; 972 } 973 974 975 const struct TALER_WireFeeSet * 976 TEH_wire_fees_by_time ( 977 struct GNUNET_TIME_Timestamp ts, 978 const char *method) 979 { 980 struct WireStateHandle *wsh = get_wire_state (); 981 982 for (struct WireFeeSet *wfs = wsh->wfs_head; 983 NULL != wfs; 984 wfs = wfs->next) 985 { 986 if (0 != strcmp (method, 987 wfs->method)) 988 continue; 989 if ( (GNUNET_TIME_timestamp_cmp (wfs->start_date, 990 >, 991 ts)) || 992 (GNUNET_TIME_timestamp_cmp (ts, 993 >=, 994 wfs->end_date)) ) 995 continue; 996 return &wfs->fees; 997 } 998 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 999 "No wire fees for method `%s' at %s configured\n", 1000 method, 1001 GNUNET_TIME_timestamp2s (ts)); 1002 return NULL; 1003 } 1004 1005 1006 /** 1007 * Function called to forcefully resume suspended keys requests. 1008 * 1009 * @param cls unused, NULL 1010 */ 1011 static void 1012 keys_timeout_cb (void *cls) 1013 { 1014 struct SuspendedKeysRequests *skr; 1015 1016 (void) cls; 1017 keys_tt = NULL; 1018 while (NULL != (skr = skr_head)) 1019 { 1020 if (GNUNET_TIME_absolute_is_future (skr->timeout)) 1021 break; 1022 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1023 "Resuming /keys request due to timeout\n"); 1024 GNUNET_CONTAINER_DLL_remove (skr_head, 1025 skr_tail, 1026 skr); 1027 skr_size--; 1028 MHD_resume_connection (skr->connection); 1029 TALER_MHD_daemon_trigger (); 1030 GNUNET_free (skr); 1031 } 1032 if (NULL == skr) 1033 return; 1034 keys_tt = GNUNET_SCHEDULER_add_at (skr->timeout, 1035 &keys_timeout_cb, 1036 NULL); 1037 } 1038 1039 1040 /** 1041 * Suspend /keys request while we (hopefully) are waiting to be 1042 * provisioned with key material. 1043 * 1044 * @param[in] connection to suspend 1045 */ 1046 static MHD_RESULT 1047 suspend_request (struct MHD_Connection *connection) 1048 { 1049 struct SuspendedKeysRequests *skr; 1050 1051 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1052 "Suspending /keys request until key material changes\n"); 1053 if (terminating) 1054 { 1055 return TALER_MHD_reply_with_error (connection, 1056 MHD_HTTP_INTERNAL_SERVER_ERROR, 1057 TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING, 1058 "Exchange terminating"); 1059 } 1060 skr = GNUNET_new (struct SuspendedKeysRequests); 1061 skr->connection = connection; 1062 MHD_suspend_connection (connection); 1063 GNUNET_CONTAINER_DLL_insert (skr_head, 1064 skr_tail, 1065 skr); 1066 skr_size++; 1067 skr->timeout = GNUNET_TIME_relative_to_absolute (KEYS_TIMEOUT); 1068 if (NULL == keys_tt) 1069 { 1070 keys_tt = GNUNET_SCHEDULER_add_at (skr->timeout, 1071 &keys_timeout_cb, 1072 NULL); 1073 } 1074 while (skr_size > SKR_LIMIT) 1075 { 1076 skr = skr_tail; 1077 GNUNET_CONTAINER_DLL_remove (skr_head, 1078 skr_tail, 1079 skr); 1080 skr_size--; 1081 MHD_resume_connection (skr->connection); 1082 TALER_MHD_daemon_trigger (); 1083 GNUNET_free (skr); 1084 } 1085 return MHD_YES; 1086 } 1087 1088 1089 /** 1090 * Called on each denomination key. Checks that the key still works. 1091 * 1092 * @param cls NULL 1093 * @param hc denomination hash (unused) 1094 * @param value a `struct TEH_DenominationKey` 1095 * @return #GNUNET_OK 1096 */ 1097 static enum GNUNET_GenericReturnValue 1098 check_dk (void *cls, 1099 const struct GNUNET_HashCode *hc, 1100 void *value) 1101 { 1102 struct TEH_DenominationKey *dk = value; 1103 1104 (void) cls; 1105 (void) hc; 1106 switch (dk->denom_pub.bsign_pub_key->cipher) 1107 { 1108 case GNUNET_CRYPTO_BSA_INVALID: 1109 break; 1110 case GNUNET_CRYPTO_BSA_RSA: 1111 GNUNET_assert (GNUNET_CRYPTO_rsa_public_key_check ( 1112 dk->denom_pub.bsign_pub_key->details.rsa_public_key)); 1113 return GNUNET_OK; 1114 case GNUNET_CRYPTO_BSA_CS: 1115 /* nothing to do for GNUNET_CRYPTO_BSA_CS */ 1116 return GNUNET_OK; 1117 } 1118 GNUNET_assert (0); 1119 return GNUNET_SYSERR; 1120 } 1121 1122 1123 void 1124 TEH_check_invariants () 1125 { 1126 struct TEH_KeyStateHandle *ksh; 1127 1128 if (0 == TEH_check_invariants_flag) 1129 return; 1130 ksh = TEH_keys_get_state (); 1131 if (NULL == ksh) 1132 return; 1133 GNUNET_CONTAINER_multihashmap_iterate (ksh->denomkey_map, 1134 &check_dk, 1135 NULL); 1136 } 1137 1138 1139 void 1140 TEH_resume_keys_requests (bool do_shutdown) 1141 { 1142 struct SuspendedKeysRequests *skr; 1143 1144 if (do_shutdown) 1145 terminating = true; 1146 while (NULL != (skr = skr_head)) 1147 { 1148 GNUNET_CONTAINER_DLL_remove (skr_head, 1149 skr_tail, 1150 skr); 1151 skr_size--; 1152 MHD_resume_connection (skr->connection); 1153 TALER_MHD_daemon_trigger (); 1154 GNUNET_free (skr); 1155 } 1156 GNUNET_assert (0 == skr_size); 1157 } 1158 1159 1160 /** 1161 * Clear memory for responses to "/keys" in @a ksh. 1162 * 1163 * @param[in,out] ksh key state to update 1164 */ 1165 static void 1166 clear_response_cache (struct TEH_KeyStateHandle *ksh) 1167 { 1168 for (unsigned int i = 0; i<ksh->krd_array_length; i++) 1169 { 1170 struct KeysResponseData *krd = &ksh->krd_array[i]; 1171 1172 MHD_destroy_response (krd->response_compressed); 1173 MHD_destroy_response (krd->response_uncompressed); 1174 GNUNET_free (krd->etag); 1175 } 1176 GNUNET_array_grow (ksh->krd_array, 1177 ksh->krd_array_length, 1178 0); 1179 } 1180 1181 1182 /** 1183 * Check that the given RSA security module's public key is the one 1184 * we have pinned. If it does not match, we die hard. 1185 * 1186 * @param sm_pub RSA security module public key to check 1187 */ 1188 static void 1189 check_denom_rsa_sm_pub (const struct TALER_SecurityModulePublicKeyP *sm_pub) 1190 { 1191 if (0 != 1192 GNUNET_memcmp (sm_pub, 1193 &denom_rsa_sm_pub)) 1194 { 1195 if (! GNUNET_is_zero (&denom_rsa_sm_pub)) 1196 { 1197 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1198 "Our RSA security module changed its key. This must not happen.\n"); 1199 GNUNET_assert (0); 1200 } 1201 denom_rsa_sm_pub = *sm_pub; /* TOFU ;-) */ 1202 } 1203 } 1204 1205 1206 /** 1207 * Check that the given CS security module's public key is the one 1208 * we have pinned. If it does not match, we die hard. 1209 * 1210 * @param sm_pub RSA security module public key to check 1211 */ 1212 static void 1213 check_denom_cs_sm_pub (const struct TALER_SecurityModulePublicKeyP *sm_pub) 1214 { 1215 if (0 != 1216 GNUNET_memcmp (sm_pub, 1217 &denom_cs_sm_pub)) 1218 { 1219 if (! GNUNET_is_zero (&denom_cs_sm_pub)) 1220 { 1221 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1222 "Our CS security module changed its key. This must not happen.\n"); 1223 GNUNET_assert (0); 1224 } 1225 denom_cs_sm_pub = *sm_pub; /* TOFU ;-) */ 1226 } 1227 } 1228 1229 1230 /** 1231 * Check that the given EdDSA security module's public key is the one 1232 * we have pinned. If it does not match, we die hard. 1233 * 1234 * @param sm_pub EdDSA security module public key to check 1235 */ 1236 static void 1237 check_esign_sm_pub (const struct TALER_SecurityModulePublicKeyP *sm_pub) 1238 { 1239 if (0 != 1240 GNUNET_memcmp (sm_pub, 1241 &esign_sm_pub)) 1242 { 1243 if (! GNUNET_is_zero (&esign_sm_pub)) 1244 { 1245 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1246 "Our EdDSA security module changed its key. This must not happen.\n"); 1247 GNUNET_assert (0); 1248 } 1249 esign_sm_pub = *sm_pub; /* TOFU ;-) */ 1250 } 1251 } 1252 1253 1254 /** 1255 * Helper function for #destroy_key_helpers to free all entries 1256 * in the `denom_keys` map. 1257 * 1258 * @param cls the `struct HelperDenomination` 1259 * @param h_denom_pub hash of the denomination public key 1260 * @param value the `struct HelperDenomination` to release 1261 * @return #GNUNET_OK (continue to iterate) 1262 */ 1263 static enum GNUNET_GenericReturnValue 1264 free_denom_cb (void *cls, 1265 const struct GNUNET_HashCode *h_denom_pub, 1266 void *value) 1267 { 1268 struct HelperDenomination *hd = value; 1269 1270 (void) cls; 1271 (void) h_denom_pub; 1272 TALER_denom_pub_free (&hd->denom_pub); 1273 GNUNET_free (hd->section_name); 1274 GNUNET_free (hd); 1275 return GNUNET_OK; 1276 } 1277 1278 1279 /** 1280 * Helper function for #destroy_key_helpers to free all entries 1281 * in the `esign_keys` map. 1282 * 1283 * @param cls the `struct HelperSignkey` 1284 * @param pid unused, matches the exchange public key 1285 * @param value the `struct HelperSignkey` to release 1286 * @return #GNUNET_OK (continue to iterate) 1287 */ 1288 static enum GNUNET_GenericReturnValue 1289 free_esign_cb (void *cls, 1290 const struct GNUNET_PeerIdentity *pid, 1291 void *value) 1292 { 1293 struct HelperSignkey *hsk = value; 1294 1295 (void) cls; 1296 (void) pid; 1297 GNUNET_free (hsk); 1298 return GNUNET_OK; 1299 } 1300 1301 1302 /** 1303 * Destroy helper state. Does NOT call free() on @a hs, as that 1304 * state is not separately allocated! Dual to #setup_key_helpers(). 1305 * 1306 * @param[in] hs helper state to free, but NOT the @a hs pointer itself! 1307 */ 1308 static void 1309 destroy_key_helpers (struct HelperState *hs) 1310 { 1311 GNUNET_CONTAINER_multihashmap_iterate (hs->denom_keys, 1312 &free_denom_cb, 1313 hs); 1314 GNUNET_CONTAINER_multihashmap_destroy (hs->rsa_keys); 1315 hs->rsa_keys = NULL; 1316 GNUNET_CONTAINER_multihashmap_destroy (hs->cs_keys); 1317 hs->cs_keys = NULL; 1318 GNUNET_CONTAINER_multihashmap_destroy (hs->denom_keys); 1319 hs->denom_keys = NULL; 1320 GNUNET_CONTAINER_multipeermap_iterate (hs->esign_keys, 1321 &free_esign_cb, 1322 hs); 1323 GNUNET_CONTAINER_multipeermap_destroy (hs->esign_keys); 1324 hs->esign_keys = NULL; 1325 if (NULL != hs->rsadh) 1326 { 1327 TALER_CRYPTO_helper_rsa_disconnect (hs->rsadh); 1328 hs->rsadh = NULL; 1329 } 1330 if (NULL != hs->csdh) 1331 { 1332 TALER_CRYPTO_helper_cs_disconnect (hs->csdh); 1333 hs->csdh = NULL; 1334 } 1335 if (NULL != hs->esh) 1336 { 1337 TALER_CRYPTO_helper_esign_disconnect (hs->esh); 1338 hs->esh = NULL; 1339 } 1340 } 1341 1342 1343 /** 1344 * Looks up the AGE_RESTRICTED setting for a denomination in the config and 1345 * returns the age restriction (mask) accordingly. 1346 * 1347 * @param section_name Section in the configuration for the particular 1348 * denomination. 1349 */ 1350 static struct TALER_AgeMask 1351 load_age_mask (const char *section_name) 1352 { 1353 static const struct TALER_AgeMask null_mask = {0}; 1354 enum GNUNET_GenericReturnValue ret; 1355 1356 if (GNUNET_OK != (GNUNET_CONFIGURATION_have_value ( 1357 TEH_cfg, 1358 section_name, 1359 "AGE_RESTRICTED"))) 1360 return null_mask; 1361 1362 if (GNUNET_SYSERR == 1363 (ret = GNUNET_CONFIGURATION_get_value_yesno (TEH_cfg, 1364 section_name, 1365 "AGE_RESTRICTED"))) 1366 { 1367 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, 1368 section_name, 1369 "AGE_RESTRICTED", 1370 "Value must be YES or NO\n"); 1371 return null_mask; 1372 } 1373 1374 if (GNUNET_OK == ret) 1375 { 1376 if (! TEH_age_restriction_enabled) 1377 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 1378 "age restriction set in section %s, yet, age restriction is not enabled\n", 1379 section_name); 1380 return TEH_age_restriction_config.mask; 1381 } 1382 1383 1384 return null_mask; 1385 } 1386 1387 1388 /** 1389 * Function called with information about available keys for signing. Usually 1390 * only called once per key upon connect. Also called again in case a key is 1391 * being revoked, in that case with an @a end_time of zero. 1392 * 1393 * @param cls closure with the `struct HelperState *` 1394 * @param section_name name of the denomination type in the configuration; 1395 * NULL if the key has been revoked or purged 1396 * @param start_time when does the key become available for signing; 1397 * zero if the key has been revoked or purged 1398 * @param validity_duration how long does the key remain available for signing; 1399 * zero if the key has been revoked or purged 1400 * @param h_rsa hash of the @a denom_pub that is available (or was purged) 1401 * @param bs_pub the public key itself, NULL if the key was revoked or purged 1402 * @param sm_pub public key of the security module, NULL if the key was revoked or purged 1403 * @param sm_sig signature from the security module 1404 */ 1405 static void 1406 helper_rsa_cb ( 1407 void *cls, 1408 const char *section_name, 1409 struct GNUNET_TIME_Timestamp start_time, 1410 struct GNUNET_TIME_Relative validity_duration, 1411 const struct TALER_RsaPubHashP *h_rsa, 1412 struct GNUNET_CRYPTO_BlindSignPublicKey *bs_pub, 1413 const struct TALER_SecurityModulePublicKeyP *sm_pub, 1414 const struct TALER_SecurityModuleSignatureP *sm_sig) 1415 { 1416 struct HelperState *hs = cls; 1417 struct HelperDenomination *hd; 1418 1419 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1420 "RSA helper announces key %s for denomination type %s with validity %s\n", 1421 GNUNET_h2s (&h_rsa->hash), 1422 section_name, 1423 GNUNET_STRINGS_relative_time_to_string (validity_duration, 1424 GNUNET_NO)); 1425 key_generation++; 1426 TEH_resume_keys_requests (false); 1427 hd = GNUNET_CONTAINER_multihashmap_get (hs->rsa_keys, 1428 &h_rsa->hash); 1429 if (NULL != hd) 1430 { 1431 /* should be just an update (revocation!), so update existing entry */ 1432 hd->validity_duration = validity_duration; 1433 return; 1434 } 1435 GNUNET_assert (NULL != sm_pub); 1436 check_denom_rsa_sm_pub (sm_pub); 1437 hd = GNUNET_new (struct HelperDenomination); 1438 hd->start_time = start_time; 1439 hd->validity_duration = validity_duration; 1440 hd->h_details.h_rsa = *h_rsa; 1441 hd->sm_sig = *sm_sig; 1442 GNUNET_assert (GNUNET_CRYPTO_BSA_RSA == bs_pub->cipher); 1443 hd->denom_pub.bsign_pub_key = 1444 GNUNET_CRYPTO_bsign_pub_incref (bs_pub); 1445 /* load the age mask for the denomination, if applicable */ 1446 hd->denom_pub.age_mask = load_age_mask (section_name); 1447 TALER_denom_pub_hash (&hd->denom_pub, 1448 &hd->h_denom_pub); 1449 hd->section_name = GNUNET_strdup (section_name); 1450 GNUNET_assert ( 1451 GNUNET_OK == 1452 GNUNET_CONTAINER_multihashmap_put ( 1453 hs->denom_keys, 1454 &hd->h_denom_pub.hash, 1455 hd, 1456 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); 1457 GNUNET_assert ( 1458 GNUNET_OK == 1459 GNUNET_CONTAINER_multihashmap_put ( 1460 hs->rsa_keys, 1461 &hd->h_details.h_rsa.hash, 1462 hd, 1463 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); 1464 } 1465 1466 1467 /** 1468 * Function called with information about available CS keys for signing. Usually 1469 * only called once per key upon connect. Also called again in case a key is 1470 * being revoked, in that case with an @a end_time of zero. 1471 * 1472 * @param cls closure with the `struct HelperState *` 1473 * @param section_name name of the denomination type in the configuration; 1474 * NULL if the key has been revoked or purged 1475 * @param start_time when does the key become available for signing; 1476 * zero if the key has been revoked or purged 1477 * @param validity_duration how long does the key remain available for signing; 1478 * zero if the key has been revoked or purged 1479 * @param h_cs hash of the @a denom_pub that is available (or was purged) 1480 * @param bs_pub the public key itself, NULL if the key was revoked or purged 1481 * @param sm_pub public key of the security module, NULL if the key was revoked or purged 1482 * @param sm_sig signature from the security module 1483 */ 1484 static void 1485 helper_cs_cb ( 1486 void *cls, 1487 const char *section_name, 1488 struct GNUNET_TIME_Timestamp start_time, 1489 struct GNUNET_TIME_Relative validity_duration, 1490 const struct TALER_CsPubHashP *h_cs, 1491 struct GNUNET_CRYPTO_BlindSignPublicKey *bs_pub, 1492 const struct TALER_SecurityModulePublicKeyP *sm_pub, 1493 const struct TALER_SecurityModuleSignatureP *sm_sig) 1494 { 1495 struct HelperState *hs = cls; 1496 struct HelperDenomination *hd; 1497 1498 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1499 "CS helper announces key %s for denomination type %s with validity %s\n", 1500 GNUNET_h2s (&h_cs->hash), 1501 section_name, 1502 GNUNET_STRINGS_relative_time_to_string (validity_duration, 1503 GNUNET_NO)); 1504 key_generation++; 1505 TEH_resume_keys_requests (false); 1506 hd = GNUNET_CONTAINER_multihashmap_get (hs->cs_keys, 1507 &h_cs->hash); 1508 if (NULL != hd) 1509 { 1510 /* should be just an update (revocation!), so update existing entry */ 1511 hd->validity_duration = validity_duration; 1512 return; 1513 } 1514 GNUNET_assert (NULL != sm_pub); 1515 check_denom_cs_sm_pub (sm_pub); 1516 hd = GNUNET_new (struct HelperDenomination); 1517 hd->start_time = start_time; 1518 hd->validity_duration = validity_duration; 1519 hd->h_details.h_cs = *h_cs; 1520 hd->sm_sig = *sm_sig; 1521 GNUNET_assert (GNUNET_CRYPTO_BSA_CS == bs_pub->cipher); 1522 hd->denom_pub.bsign_pub_key 1523 = GNUNET_CRYPTO_bsign_pub_incref (bs_pub); 1524 /* load the age mask for the denomination, if applicable */ 1525 hd->denom_pub.age_mask = load_age_mask (section_name); 1526 TALER_denom_pub_hash (&hd->denom_pub, 1527 &hd->h_denom_pub); 1528 hd->section_name = GNUNET_strdup (section_name); 1529 GNUNET_assert ( 1530 GNUNET_OK == 1531 GNUNET_CONTAINER_multihashmap_put ( 1532 hs->denom_keys, 1533 &hd->h_denom_pub.hash, 1534 hd, 1535 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); 1536 GNUNET_assert ( 1537 GNUNET_OK == 1538 GNUNET_CONTAINER_multihashmap_put ( 1539 hs->cs_keys, 1540 &hd->h_details.h_cs.hash, 1541 hd, 1542 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); 1543 } 1544 1545 1546 /** 1547 * Function called with information about available keys for signing. Usually 1548 * only called once per key upon connect. Also called again in case a key is 1549 * being revoked, in that case with an @a end_time of zero. 1550 * 1551 * @param cls closure with the `struct HelperState *` 1552 * @param start_time when does the key become available for signing; 1553 * zero if the key has been revoked or purged 1554 * @param validity_duration how long does the key remain available for signing; 1555 * zero if the key has been revoked or purged 1556 * @param exchange_pub the public key itself, NULL if the key was revoked or purged 1557 * @param sm_pub public key of the security module, NULL if the key was revoked or purged 1558 * @param sm_sig signature from the security module 1559 */ 1560 static void 1561 helper_esign_cb ( 1562 void *cls, 1563 struct GNUNET_TIME_Timestamp start_time, 1564 struct GNUNET_TIME_Relative validity_duration, 1565 const struct TALER_ExchangePublicKeyP *exchange_pub, 1566 const struct TALER_SecurityModulePublicKeyP *sm_pub, 1567 const struct TALER_SecurityModuleSignatureP *sm_sig) 1568 { 1569 struct HelperState *hs = cls; 1570 struct HelperSignkey *hsk; 1571 struct GNUNET_PeerIdentity pid; 1572 1573 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1574 "EdDSA helper announces signing key %s with validity %s\n", 1575 TALER_B2S (exchange_pub), 1576 GNUNET_STRINGS_relative_time_to_string (validity_duration, 1577 GNUNET_NO)); 1578 key_generation++; 1579 TEH_resume_keys_requests (false); 1580 pid.public_key = exchange_pub->eddsa_pub; 1581 hsk = GNUNET_CONTAINER_multipeermap_get (hs->esign_keys, 1582 &pid); 1583 if (NULL != hsk) 1584 { 1585 /* should be just an update (revocation!), so update existing entry */ 1586 hsk->validity_duration = validity_duration; 1587 return; 1588 } 1589 GNUNET_assert (NULL != sm_pub); 1590 check_esign_sm_pub (sm_pub); 1591 hsk = GNUNET_new (struct HelperSignkey); 1592 hsk->start_time = start_time; 1593 hsk->validity_duration = validity_duration; 1594 hsk->exchange_pub = *exchange_pub; 1595 hsk->sm_sig = *sm_sig; 1596 GNUNET_assert ( 1597 GNUNET_OK == 1598 GNUNET_CONTAINER_multipeermap_put ( 1599 hs->esign_keys, 1600 &pid, 1601 hsk, 1602 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); 1603 } 1604 1605 1606 /** 1607 * Setup helper state. 1608 * 1609 * @param[out] hs helper state to initialize 1610 * @return #GNUNET_OK on success 1611 */ 1612 static enum GNUNET_GenericReturnValue 1613 setup_key_helpers (struct HelperState *hs) 1614 { 1615 hs->denom_keys 1616 = GNUNET_CONTAINER_multihashmap_create (1024, 1617 GNUNET_YES); 1618 hs->rsa_keys 1619 = GNUNET_CONTAINER_multihashmap_create (1024, 1620 GNUNET_YES); 1621 hs->cs_keys 1622 = GNUNET_CONTAINER_multihashmap_create (1024, 1623 GNUNET_YES); 1624 hs->esign_keys 1625 = GNUNET_CONTAINER_multipeermap_create (32, 1626 GNUNET_NO /* MUST BE NO! */); 1627 hs->rsadh = TALER_CRYPTO_helper_rsa_connect (TEH_cfg, 1628 "taler-exchange", 1629 &helper_rsa_cb, 1630 hs); 1631 if (NULL == hs->rsadh) 1632 return GNUNET_SYSERR; 1633 hs->csdh = TALER_CRYPTO_helper_cs_connect (TEH_cfg, 1634 "taler-exchange", 1635 &helper_cs_cb, 1636 hs); 1637 if (NULL == hs->csdh) 1638 return GNUNET_SYSERR; 1639 hs->esh = TALER_CRYPTO_helper_esign_connect (TEH_cfg, 1640 "taler-exchange", 1641 &helper_esign_cb, 1642 hs); 1643 if (NULL == hs->esh) 1644 return GNUNET_SYSERR; 1645 return GNUNET_OK; 1646 } 1647 1648 1649 /** 1650 * Synchronize helper state. Polls the key helper for updates. 1651 * 1652 * @param[in,out] hs helper state to synchronize 1653 */ 1654 static void 1655 sync_key_helpers (struct HelperState *hs) 1656 { 1657 TALER_CRYPTO_helper_rsa_poll (hs->rsadh); 1658 TALER_CRYPTO_helper_cs_poll (hs->csdh); 1659 TALER_CRYPTO_helper_esign_poll (hs->esh); 1660 } 1661 1662 1663 /** 1664 * Free denomination key data. 1665 * 1666 * @param cls a `struct TEH_KeyStateHandle`, unused 1667 * @param h_denom_pub hash of the denomination public key, unused 1668 * @param value a `struct TEH_DenominationKey` to free 1669 * @return #GNUNET_OK (continue to iterate) 1670 */ 1671 static enum GNUNET_GenericReturnValue 1672 clear_denomination_cb (void *cls, 1673 const struct GNUNET_HashCode *h_denom_pub, 1674 void *value) 1675 { 1676 struct TEH_DenominationKey *dk = value; 1677 struct TEH_AuditorSignature *as; 1678 1679 (void) cls; 1680 (void) h_denom_pub; 1681 TALER_denom_pub_free (&dk->denom_pub); 1682 while (NULL != (as = dk->as_head)) 1683 { 1684 GNUNET_CONTAINER_DLL_remove (dk->as_head, 1685 dk->as_tail, 1686 as); 1687 GNUNET_free (as); 1688 } 1689 GNUNET_free (dk); 1690 return GNUNET_OK; 1691 } 1692 1693 1694 /** 1695 * Free denomination key data. 1696 * 1697 * @param cls a `struct TEH_KeyStateHandle`, unused 1698 * @param pid the online signing key (type-disguised), unused 1699 * @param value a `struct SigningKey` to free 1700 * @return #GNUNET_OK (continue to iterate) 1701 */ 1702 static enum GNUNET_GenericReturnValue 1703 clear_signkey_cb (void *cls, 1704 const struct GNUNET_PeerIdentity *pid, 1705 void *value) 1706 { 1707 struct SigningKey *sk = value; 1708 1709 (void) cls; 1710 (void) pid; 1711 GNUNET_free (sk); 1712 return GNUNET_OK; 1713 } 1714 1715 1716 /** 1717 * Free resources associated with @a cls, possibly excluding 1718 * the helper data. 1719 * 1720 * @param[in] ksh key state to release 1721 */ 1722 static void 1723 destroy_key_state (struct TEH_KeyStateHandle *ksh) 1724 { 1725 struct TEH_GlobalFee *gf; 1726 1727 clear_response_cache (ksh); 1728 while (NULL != (gf = ksh->gf_head)) 1729 { 1730 GNUNET_CONTAINER_DLL_remove (ksh->gf_head, 1731 ksh->gf_tail, 1732 gf); 1733 GNUNET_free (gf); 1734 } 1735 GNUNET_CONTAINER_multihashmap_iterate (ksh->denomkey_map, 1736 &clear_denomination_cb, 1737 ksh); 1738 GNUNET_CONTAINER_multihashmap_destroy (ksh->denomkey_map); 1739 GNUNET_CONTAINER_multihashmap32_destroy (ksh->denomserial_map); 1740 GNUNET_CONTAINER_multipeermap_iterate (ksh->signkey_map, 1741 &clear_signkey_cb, 1742 ksh); 1743 GNUNET_CONTAINER_multipeermap_destroy (ksh->signkey_map); 1744 json_decref (ksh->auditors); 1745 ksh->auditors = NULL; 1746 json_decref (ksh->global_fees); 1747 ksh->global_fees = NULL; 1748 if (NULL != ksh->management_keys_reply) 1749 { 1750 json_decref (ksh->management_keys_reply); 1751 ksh->management_keys_reply = NULL; 1752 } 1753 GNUNET_free (ksh); 1754 } 1755 1756 1757 /** 1758 * Function called whenever another exchange process has updated 1759 * the keys data in the database. 1760 * 1761 * @param cls NULL 1762 * @param extra unused 1763 * @param extra_size number of bytes in @a extra unused 1764 */ 1765 static void 1766 keys_update_event_cb (void *cls, 1767 const void *extra, 1768 size_t extra_size) 1769 { 1770 (void) cls; 1771 (void) extra; 1772 (void) extra_size; 1773 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1774 "Received /keys update event\n"); 1775 TEH_check_invariants (); 1776 key_generation++; 1777 TEH_resume_keys_requests (false); 1778 TEH_check_invariants (); 1779 } 1780 1781 1782 enum GNUNET_GenericReturnValue 1783 TEH_keys_init () 1784 { 1785 if (GNUNET_OK != 1786 setup_key_helpers (&helpers)) 1787 { 1788 destroy_key_helpers (&helpers); 1789 return GNUNET_SYSERR; 1790 } 1791 if (GNUNET_OK != 1792 GNUNET_CONFIGURATION_get_value_time (TEH_cfg, 1793 "exchange", 1794 "SIGNKEY_LEGAL_DURATION", 1795 &signkey_legal_duration)) 1796 { 1797 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 1798 "exchange", 1799 "SIGNKEY_LEGAL_DURATION"); 1800 return GNUNET_SYSERR; 1801 } 1802 if (GNUNET_OK != 1803 GNUNET_CONFIGURATION_get_value_string (TEH_cfg, 1804 "exchange", 1805 "ASSET_TYPE", 1806 &asset_type)) 1807 { 1808 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING, 1809 "exchange", 1810 "ASSET_TYPE"); 1811 asset_type = GNUNET_strdup ("fiat"); 1812 } 1813 { 1814 struct GNUNET_DB_EventHeaderP es = { 1815 .size = htons (sizeof (es)), 1816 .type = htons (TALER_DBEVENT_EXCHANGE_KEYS_UPDATED), 1817 }; 1818 1819 keys_eh = TEH_plugin->event_listen (TEH_plugin->cls, 1820 GNUNET_TIME_UNIT_FOREVER_REL, 1821 &es, 1822 &keys_update_event_cb, 1823 NULL); 1824 if (NULL == keys_eh) 1825 { 1826 GNUNET_break (0); 1827 return GNUNET_SYSERR; 1828 } 1829 } 1830 { 1831 struct GNUNET_DB_EventHeaderP es = { 1832 .size = htons (sizeof (es)), 1833 .type = htons (TALER_DBEVENT_EXCHANGE_KEYS_UPDATED), 1834 }; 1835 1836 wire_eh = TEH_plugin->event_listen (TEH_plugin->cls, 1837 GNUNET_TIME_UNIT_FOREVER_REL, 1838 &es, 1839 &wire_update_event_cb, 1840 NULL); 1841 if (NULL == wire_eh) 1842 { 1843 GNUNET_break (0); 1844 return GNUNET_SYSERR; 1845 } 1846 } 1847 return GNUNET_OK; 1848 } 1849 1850 1851 /** 1852 * Fully clean up our state. 1853 */ 1854 void 1855 TEH_keys_finished () 1856 { 1857 if (NULL != wire_state) 1858 { 1859 destroy_wire_state (wire_state); 1860 wire_state = NULL; 1861 } 1862 if (NULL != wire_eh) 1863 { 1864 TEH_plugin->event_listen_cancel (TEH_plugin->cls, 1865 wire_eh); 1866 wire_eh = NULL; 1867 } 1868 if (NULL != keys_tt) 1869 { 1870 GNUNET_SCHEDULER_cancel (keys_tt); 1871 keys_tt = NULL; 1872 } 1873 if (NULL != key_state) 1874 destroy_key_state (key_state); 1875 if (NULL != keys_eh) 1876 { 1877 TEH_plugin->event_listen_cancel (TEH_plugin->cls, 1878 keys_eh); 1879 keys_eh = NULL; 1880 } 1881 destroy_key_helpers (&helpers); 1882 } 1883 1884 1885 /** 1886 * Function called with information about the exchange's denomination keys. 1887 * 1888 * @param cls closure with a `struct TEH_KeyStateHandle *` 1889 * @param denom_pub public key of the denomination 1890 * @param h_denom_pub hash of @a denom_pub 1891 * @param meta meta data information about the denomination type (value, expirations, fees) 1892 * @param master_sig master signature affirming the validity of this denomination 1893 * @param recoup_possible true if the key was revoked and clients can currently recoup 1894 * coins of this denomination 1895 */ 1896 static void 1897 denomination_info_cb ( 1898 void *cls, 1899 const struct TALER_DenominationPublicKey *denom_pub, 1900 const struct TALER_DenominationHashP *h_denom_pub, 1901 const struct TALER_EXCHANGEDB_DenominationKeyMetaData *meta, 1902 const struct TALER_MasterSignatureP *master_sig, 1903 bool recoup_possible) 1904 { 1905 struct TEH_KeyStateHandle *ksh = cls; 1906 struct TEH_DenominationKey *dk; 1907 1908 if (GNUNET_TIME_absolute_is_past (meta->expire_deposit.abs_time)) 1909 { 1910 /* should have been filtered by DB query already! */ 1911 GNUNET_break (0); 1912 return; 1913 } 1914 if (GNUNET_OK != 1915 TALER_exchange_offline_denom_validity_verify ( 1916 h_denom_pub, 1917 meta->start, 1918 meta->expire_withdraw, 1919 meta->expire_deposit, 1920 meta->expire_legal, 1921 &meta->value, 1922 &meta->fees, 1923 &TEH_master_public_key, 1924 master_sig)) 1925 { 1926 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1927 "Database has denomination with invalid signature. Skipping entry. Did the exchange offline public key change?\n"); 1928 return; 1929 } 1930 1931 GNUNET_assert (GNUNET_CRYPTO_BSA_INVALID != 1932 denom_pub->bsign_pub_key->cipher); 1933 if (GNUNET_TIME_absolute_is_zero (meta->start.abs_time) || 1934 GNUNET_TIME_absolute_is_zero (meta->expire_withdraw.abs_time) || 1935 GNUNET_TIME_absolute_is_zero (meta->expire_deposit.abs_time) || 1936 GNUNET_TIME_absolute_is_zero (meta->expire_legal.abs_time) ) 1937 { 1938 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1939 "Database contains invalid denomination key %s\n", 1940 GNUNET_h2s (&h_denom_pub->hash)); 1941 return; 1942 } 1943 dk = GNUNET_new (struct TEH_DenominationKey); 1944 TALER_denom_pub_copy (&dk->denom_pub, 1945 denom_pub); 1946 dk->h_denom_pub = *h_denom_pub; 1947 dk->meta = *meta; 1948 dk->master_sig = *master_sig; 1949 dk->recoup_possible = recoup_possible; 1950 dk->denom_pub.age_mask = meta->age_mask; 1951 1952 GNUNET_assert ( 1953 GNUNET_OK == 1954 GNUNET_CONTAINER_multihashmap_put (ksh->denomkey_map, 1955 &dk->h_denom_pub.hash, 1956 dk, 1957 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); 1958 { 1959 uint32_t serial32 = (uint32_t) dk->meta.serial; 1960 1961 GNUNET_assert (dk->meta.serial == (uint64_t) serial32); 1962 GNUNET_assert ( 1963 GNUNET_OK == 1964 GNUNET_CONTAINER_multihashmap32_put (ksh->denomserial_map, 1965 serial32, 1966 dk, 1967 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); 1968 } 1969 } 1970 1971 1972 /** 1973 * Function called with information about the exchange's online signing keys. 1974 * 1975 * @param cls closure with a `struct TEH_KeyStateHandle *` 1976 * @param exchange_pub the public key 1977 * @param meta meta data information about the denomination type (expirations) 1978 * @param master_sig master signature affirming the validity of this denomination 1979 */ 1980 static void 1981 signkey_info_cb ( 1982 void *cls, 1983 const struct TALER_ExchangePublicKeyP *exchange_pub, 1984 const struct TALER_EXCHANGEDB_SignkeyMetaData *meta, 1985 const struct TALER_MasterSignatureP *master_sig) 1986 { 1987 struct TEH_KeyStateHandle *ksh = cls; 1988 struct SigningKey *sk; 1989 struct GNUNET_PeerIdentity pid; 1990 1991 if (GNUNET_OK != 1992 TALER_exchange_offline_signkey_validity_verify ( 1993 exchange_pub, 1994 meta->start, 1995 meta->expire_sign, 1996 meta->expire_legal, 1997 &TEH_master_public_key, 1998 master_sig)) 1999 { 2000 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 2001 "Database has signing key with invalid signature. Skipping entry. Did the exchange offline public key change?\n"); 2002 return; 2003 } 2004 sk = GNUNET_new (struct SigningKey); 2005 sk->exchange_pub = *exchange_pub; 2006 sk->meta = *meta; 2007 sk->master_sig = *master_sig; 2008 pid.public_key = exchange_pub->eddsa_pub; 2009 GNUNET_assert ( 2010 GNUNET_OK == 2011 GNUNET_CONTAINER_multipeermap_put (ksh->signkey_map, 2012 &pid, 2013 sk, 2014 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); 2015 } 2016 2017 2018 /** 2019 * Closure for #get_auditor_sigs. 2020 */ 2021 struct GetAuditorSigsContext 2022 { 2023 /** 2024 * Where to store the matching signatures. 2025 */ 2026 json_t *denom_keys; 2027 2028 /** 2029 * Public key of the auditor to match against. 2030 */ 2031 const struct TALER_AuditorPublicKeyP *auditor_pub; 2032 }; 2033 2034 2035 /** 2036 * Extract the auditor signatures matching the auditor's public 2037 * key from the @a value and generate the respective JSON. 2038 * 2039 * @param cls a `struct GetAuditorSigsContext` 2040 * @param h_denom_pub hash of the denomination public key 2041 * @param value a `struct TEH_DenominationKey` 2042 * @return #GNUNET_OK (continue to iterate) 2043 */ 2044 static enum GNUNET_GenericReturnValue 2045 get_auditor_sigs (void *cls, 2046 const struct GNUNET_HashCode *h_denom_pub, 2047 void *value) 2048 { 2049 struct GetAuditorSigsContext *ctx = cls; 2050 struct TEH_DenominationKey *dk = value; 2051 2052 for (struct TEH_AuditorSignature *as = dk->as_head; 2053 NULL != as; 2054 as = as->next) 2055 { 2056 if (0 != 2057 GNUNET_memcmp (ctx->auditor_pub, 2058 &as->apub)) 2059 continue; 2060 GNUNET_break (0 == 2061 json_array_append_new ( 2062 ctx->denom_keys, 2063 GNUNET_JSON_PACK ( 2064 GNUNET_JSON_pack_data_auto ("denom_pub_h", 2065 h_denom_pub), 2066 GNUNET_JSON_pack_data_auto ("auditor_sig", 2067 &as->asig)))); 2068 } 2069 return GNUNET_OK; 2070 } 2071 2072 2073 /** 2074 * Function called with information about the exchange's auditors. 2075 * 2076 * @param cls closure with a `struct TEH_KeyStateHandle *` 2077 * @param auditor_pub the public key of the auditor 2078 * @param auditor_url URL of the REST API of the auditor 2079 * @param auditor_name human readable official name of the auditor 2080 */ 2081 static void 2082 auditor_info_cb ( 2083 void *cls, 2084 const struct TALER_AuditorPublicKeyP *auditor_pub, 2085 const char *auditor_url, 2086 const char *auditor_name) 2087 { 2088 struct TEH_KeyStateHandle *ksh = cls; 2089 struct GetAuditorSigsContext ctx; 2090 2091 ctx.denom_keys = json_array (); 2092 GNUNET_assert (NULL != ctx.denom_keys); 2093 ctx.auditor_pub = auditor_pub; 2094 GNUNET_CONTAINER_multihashmap_iterate (ksh->denomkey_map, 2095 &get_auditor_sigs, 2096 &ctx); 2097 GNUNET_break (0 == 2098 json_array_append_new ( 2099 ksh->auditors, 2100 GNUNET_JSON_PACK ( 2101 GNUNET_JSON_pack_string ("auditor_name", 2102 auditor_name), 2103 GNUNET_JSON_pack_data_auto ("auditor_pub", 2104 auditor_pub), 2105 GNUNET_JSON_pack_string ("auditor_url", 2106 auditor_url), 2107 GNUNET_JSON_pack_array_steal ("denomination_keys", 2108 ctx.denom_keys)))); 2109 } 2110 2111 2112 /** 2113 * Function called with information about the denominations 2114 * audited by the exchange's auditors. 2115 * 2116 * @param cls closure with a `struct TEH_KeyStateHandle *` 2117 * @param auditor_pub the public key of an auditor 2118 * @param h_denom_pub hash of a denomination key audited by this auditor 2119 * @param auditor_sig signature from the auditor affirming this 2120 */ 2121 static void 2122 auditor_denom_cb ( 2123 void *cls, 2124 const struct TALER_AuditorPublicKeyP *auditor_pub, 2125 const struct TALER_DenominationHashP *h_denom_pub, 2126 const struct TALER_AuditorSignatureP *auditor_sig) 2127 { 2128 struct TEH_KeyStateHandle *ksh = cls; 2129 struct TEH_DenominationKey *dk; 2130 struct TEH_AuditorSignature *as; 2131 2132 dk = GNUNET_CONTAINER_multihashmap_get (ksh->denomkey_map, 2133 &h_denom_pub->hash); 2134 if (NULL == dk) 2135 { 2136 /* Odd, this should be impossible as per foreign key 2137 constraint on 'auditor_denom_sigs'! Well, we can 2138 safely continue anyway, so let's just log it. */ 2139 GNUNET_break (0); 2140 return; 2141 } 2142 as = GNUNET_new (struct TEH_AuditorSignature); 2143 as->asig = *auditor_sig; 2144 as->apub = *auditor_pub; 2145 GNUNET_CONTAINER_DLL_insert (dk->as_head, 2146 dk->as_tail, 2147 as); 2148 } 2149 2150 2151 /** 2152 * Closure for #add_sign_key_cb. 2153 */ 2154 struct SignKeyCtx 2155 { 2156 /** 2157 * What is the current rotation frequency for signing keys. Updated. 2158 */ 2159 struct GNUNET_TIME_Relative min_sk_frequency; 2160 2161 /** 2162 * JSON array of signing keys (being created). 2163 */ 2164 json_t *signkeys; 2165 }; 2166 2167 2168 /** 2169 * Function called for all signing keys, used to build up the 2170 * respective JSON response. 2171 * 2172 * @param cls a `struct SignKeyCtx *` with the array to append keys to 2173 * @param pid the exchange public key (in type disguise) 2174 * @param value a `struct SigningKey` 2175 * @return #GNUNET_OK (continue to iterate) 2176 */ 2177 static enum GNUNET_GenericReturnValue 2178 add_sign_key_cb (void *cls, 2179 const struct GNUNET_PeerIdentity *pid, 2180 void *value) 2181 { 2182 struct SignKeyCtx *ctx = cls; 2183 struct SigningKey *sk = value; 2184 2185 (void) pid; 2186 if (GNUNET_TIME_absolute_is_future (sk->meta.expire_sign.abs_time)) 2187 { 2188 ctx->min_sk_frequency = 2189 GNUNET_TIME_relative_min (ctx->min_sk_frequency, 2190 GNUNET_TIME_absolute_get_difference ( 2191 sk->meta.start.abs_time, 2192 sk->meta.expire_sign.abs_time)); 2193 } 2194 GNUNET_assert ( 2195 0 == 2196 json_array_append_new ( 2197 ctx->signkeys, 2198 GNUNET_JSON_PACK ( 2199 GNUNET_JSON_pack_timestamp ("stamp_start", 2200 sk->meta.start), 2201 GNUNET_JSON_pack_timestamp ("stamp_expire", 2202 sk->meta.expire_sign), 2203 GNUNET_JSON_pack_timestamp ("stamp_end", 2204 sk->meta.expire_legal), 2205 GNUNET_JSON_pack_data_auto ("master_sig", 2206 &sk->master_sig), 2207 GNUNET_JSON_pack_data_auto ("key", 2208 &sk->exchange_pub)))); 2209 return GNUNET_OK; 2210 } 2211 2212 2213 /** 2214 * Closure for #add_denom_key_cb. 2215 */ 2216 struct DenomKeyCtx 2217 { 2218 /** 2219 * Heap for sorting active denomination keys by start time. 2220 */ 2221 struct GNUNET_CONTAINER_Heap *heap; 2222 2223 /** 2224 * JSON array of revoked denomination keys. 2225 */ 2226 json_t *recoup; 2227 2228 /** 2229 * What is the minimum key rotation frequency of 2230 * valid denomination keys? 2231 */ 2232 struct GNUNET_TIME_Relative min_dk_frequency; 2233 }; 2234 2235 2236 /** 2237 * Function called for all denomination keys, used to build up the 2238 * JSON list of *revoked* denomination keys and the 2239 * heap of non-revoked denomination keys by timeout. 2240 * 2241 * @param cls a `struct DenomKeyCtx` 2242 * @param h_denom_pub hash of the denomination key 2243 * @param value a `struct TEH_DenominationKey` 2244 * @return #GNUNET_OK (continue to iterate) 2245 */ 2246 static enum GNUNET_GenericReturnValue 2247 add_denom_key_cb (void *cls, 2248 const struct GNUNET_HashCode *h_denom_pub, 2249 void *value) 2250 { 2251 struct DenomKeyCtx *dkc = cls; 2252 struct TEH_DenominationKey *dk = value; 2253 2254 if (dk->recoup_possible) 2255 { 2256 GNUNET_assert ( 2257 0 == 2258 json_array_append_new ( 2259 dkc->recoup, 2260 GNUNET_JSON_PACK ( 2261 GNUNET_JSON_pack_data_auto ("h_denom_pub", 2262 h_denom_pub)))); 2263 } 2264 else 2265 { 2266 if (GNUNET_TIME_absolute_is_future (dk->meta.start.abs_time)) 2267 { 2268 dkc->min_dk_frequency = 2269 GNUNET_TIME_relative_min (dkc->min_dk_frequency, 2270 GNUNET_TIME_absolute_get_difference ( 2271 dk->meta.start.abs_time, 2272 dk->meta.expire_withdraw.abs_time)); 2273 } 2274 (void) GNUNET_CONTAINER_heap_insert (dkc->heap, 2275 dk, 2276 dk->meta.start.abs_time.abs_value_us); 2277 } 2278 return GNUNET_OK; 2279 } 2280 2281 2282 /** 2283 * Add the headers we want to set for every /keys response. 2284 * 2285 * @param cls the key state to use 2286 * @param[in,out] response the response to modify 2287 */ 2288 static void 2289 setup_general_response_headers (void *cls, 2290 struct MHD_Response *response) 2291 { 2292 struct TEH_KeyStateHandle *ksh = cls; 2293 char dat[128]; 2294 2295 TALER_MHD_add_global_headers (response, 2296 true); 2297 GNUNET_break (MHD_YES == 2298 MHD_add_response_header (response, 2299 MHD_HTTP_HEADER_CONTENT_TYPE, 2300 "application/json")); 2301 GNUNET_break (MHD_YES == 2302 MHD_add_response_header (response, 2303 MHD_HTTP_HEADER_CACHE_CONTROL, 2304 "public,must-revalidate,max-age=86400") 2305 ); 2306 if (! GNUNET_TIME_relative_is_zero (ksh->rekey_frequency)) 2307 { 2308 struct GNUNET_TIME_Relative r; 2309 struct GNUNET_TIME_Absolute a; 2310 struct GNUNET_TIME_Timestamp km; 2311 struct GNUNET_TIME_Timestamp m; 2312 struct GNUNET_TIME_Timestamp we; 2313 2314 r = GNUNET_TIME_relative_min (TEH_max_keys_caching, 2315 ksh->rekey_frequency); 2316 a = GNUNET_TIME_relative_to_absolute (r); 2317 /* Round up to next full day to ensure the expiration 2318 time does not become a fingerprint! */ 2319 a = GNUNET_TIME_absolute_round_down (a, 2320 GNUNET_TIME_UNIT_DAYS); 2321 a = GNUNET_TIME_absolute_add (a, 2322 GNUNET_TIME_UNIT_DAYS); 2323 km = GNUNET_TIME_absolute_to_timestamp (a); 2324 we = GNUNET_TIME_absolute_to_timestamp (wire_state->cache_expiration); 2325 m = GNUNET_TIME_timestamp_min (we, 2326 km); 2327 TALER_MHD_get_date_string (m.abs_time, 2328 dat); 2329 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 2330 "Setting /keys 'Expires' header to '%s' (rekey frequency is %s)\n", 2331 dat, 2332 GNUNET_TIME_relative2s (ksh->rekey_frequency, 2333 false)); 2334 GNUNET_break (MHD_YES == 2335 MHD_add_response_header (response, 2336 MHD_HTTP_HEADER_EXPIRES, 2337 dat)); 2338 ksh->signature_expires 2339 = GNUNET_TIME_timestamp_min (m, 2340 ksh->signature_expires); 2341 } 2342 /* Set cache control headers: our response varies depending on these headers */ 2343 GNUNET_break (MHD_YES == 2344 MHD_add_response_header (response, 2345 MHD_HTTP_HEADER_VARY, 2346 MHD_HTTP_HEADER_ACCEPT_ENCODING)); 2347 } 2348 2349 2350 /** 2351 * Initialize @a krd using the given values for @a signkeys, 2352 * @a recoup and @a denoms. 2353 * 2354 * @param[in,out] ksh key state handle we build @a krd for 2355 * @param[in] denom_keys_hash hash over all the denomination keys in @a denoms 2356 * @param last_cherry_pick_date timestamp to use 2357 * @param[in,out] signkeys list of sign keys to return 2358 * @param[in,out] recoup list of revoked keys to return 2359 * @param[in,out] grouped_denominations list of grouped denominations to return 2360 * @return #GNUNET_OK on success 2361 */ 2362 static enum GNUNET_GenericReturnValue 2363 create_krd (struct TEH_KeyStateHandle *ksh, 2364 const struct GNUNET_HashCode *denom_keys_hash, 2365 struct GNUNET_TIME_Timestamp last_cherry_pick_date, 2366 json_t *signkeys, 2367 json_t *recoup, 2368 json_t *grouped_denominations) 2369 { 2370 struct KeysResponseData krd; 2371 struct TALER_ExchangePublicKeyP exchange_pub; 2372 struct TALER_ExchangeSignatureP exchange_sig; 2373 struct WireStateHandle *wsh; 2374 json_t *keys; 2375 2376 wsh = get_wire_state (); 2377 if (! wsh->ready) 2378 { 2379 GNUNET_break (0); 2380 return GNUNET_SYSERR; 2381 } 2382 GNUNET_assert (! GNUNET_TIME_absolute_is_zero ( 2383 last_cherry_pick_date.abs_time)); 2384 GNUNET_assert (NULL != signkeys); 2385 GNUNET_assert (NULL != recoup); 2386 GNUNET_assert (NULL != grouped_denominations); 2387 GNUNET_assert (NULL != ksh->auditors); 2388 GNUNET_assert (NULL != TEH_currency); 2389 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 2390 "Creating /keys at cherry pick date %s\n", 2391 GNUNET_TIME_timestamp2s (last_cherry_pick_date)); 2392 2393 /* Sign hash over master signatures of all denomination keys until this time 2394 (in reverse order). */ 2395 { 2396 enum TALER_ErrorCode ec; 2397 2398 if (TALER_EC_NONE != 2399 (ec = 2400 TALER_exchange_online_key_set_sign ( 2401 &TEH_keys_exchange_sign2_, 2402 ksh, 2403 last_cherry_pick_date, 2404 denom_keys_hash, 2405 &exchange_pub, 2406 &exchange_sig))) 2407 { 2408 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 2409 "Could not create key response data: cannot sign (%s)\n", 2410 TALER_ErrorCode_get_hint (ec)); 2411 return GNUNET_SYSERR; 2412 } 2413 } 2414 2415 { 2416 const struct SigningKey *sk; 2417 2418 sk = GNUNET_CONTAINER_multipeermap_get ( 2419 ksh->signkey_map, 2420 (const struct GNUNET_PeerIdentity *) &exchange_pub); 2421 ksh->signature_expires = GNUNET_TIME_timestamp_min (sk->meta.expire_sign, 2422 ksh->signature_expires); 2423 } 2424 2425 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 2426 "Build /keys data with %u wire accounts\n", 2427 (unsigned int) json_array_size ( 2428 json_object_get (wsh->json_reply, 2429 "accounts"))); 2430 2431 keys = GNUNET_JSON_PACK ( 2432 GNUNET_JSON_pack_string ("version", 2433 EXCHANGE_PROTOCOL_VERSION), 2434 GNUNET_JSON_pack_string ("base_url", 2435 TEH_base_url), 2436 GNUNET_JSON_pack_string ("currency", 2437 TEH_currency), 2438 GNUNET_JSON_pack_allow_null ( 2439 GNUNET_JSON_pack_string ( 2440 "bank_compliance_language", 2441 TEH_bank_compliance_language)), 2442 GNUNET_JSON_pack_object_steal ( 2443 "currency_specification", 2444 TALER_JSON_currency_specs_to_json (TEH_cspec)), 2445 GNUNET_JSON_pack_array_incref ( 2446 "hard_limits", 2447 TEH_hard_limits), 2448 GNUNET_JSON_pack_array_incref ( 2449 "zero_limits", 2450 TEH_zero_limits), 2451 TALER_JSON_pack_amount ("stefan_abs", 2452 &TEH_stefan_abs), 2453 TALER_JSON_pack_amount ("stefan_log", 2454 &TEH_stefan_log), 2455 GNUNET_JSON_pack_double ("stefan_lin", 2456 (double) TEH_stefan_lin), 2457 GNUNET_JSON_pack_string ("asset_type", 2458 asset_type), 2459 GNUNET_JSON_pack_bool ("kyc_enabled", 2460 GNUNET_YES == TEH_enable_kyc), 2461 GNUNET_JSON_pack_bool ("disable_direct_deposit", 2462 GNUNET_YES == TEH_disable_direct_deposit), 2463 GNUNET_JSON_pack_bool ("rewards_allowed", 2464 false), 2465 GNUNET_JSON_pack_data_auto ("master_public_key", 2466 &TEH_master_public_key), 2467 GNUNET_JSON_pack_time_rel ("reserve_closing_delay", 2468 TEH_reserve_closing_delay), 2469 GNUNET_JSON_pack_array_incref ("signkeys", 2470 signkeys), 2471 GNUNET_JSON_pack_array_incref ("recoup", 2472 recoup), 2473 GNUNET_JSON_pack_array_incref ("wads", 2474 json_object_get (wsh->json_reply, 2475 "wads")), 2476 GNUNET_JSON_pack_array_incref ("accounts", 2477 json_object_get (wsh->json_reply, 2478 "accounts")), 2479 GNUNET_JSON_pack_object_incref ("wire_fees", 2480 json_object_get (wsh->json_reply, 2481 "fees")), 2482 GNUNET_JSON_pack_array_incref ("denominations", 2483 grouped_denominations), 2484 GNUNET_JSON_pack_array_incref ("auditors", 2485 ksh->auditors), 2486 GNUNET_JSON_pack_array_incref ("global_fees", 2487 ksh->global_fees), 2488 GNUNET_JSON_pack_timestamp ("list_issue_date", 2489 last_cherry_pick_date), 2490 GNUNET_JSON_pack_allow_null ( 2491 GNUNET_JSON_pack_array_steal ( 2492 "wallet_balance_limit_without_kyc", 2493 TALER_KYCLOGIC_get_wallet_thresholds ())), 2494 GNUNET_JSON_pack_allow_null ( 2495 GNUNET_JSON_pack_string ("shopping_url", 2496 TEH_shopping_url)), 2497 TALER_JSON_pack_amount ("tiny_amount", 2498 &TEH_tiny_amount), 2499 GNUNET_JSON_pack_data_auto ("exchange_pub", 2500 &exchange_pub), 2501 GNUNET_JSON_pack_data_auto ("exchange_sig", 2502 &exchange_sig)); 2503 GNUNET_assert (NULL != keys); 2504 /* Signal support for the configured, enabled extensions. */ 2505 { 2506 json_t *extensions = json_object (); 2507 bool has_extensions = false; 2508 2509 GNUNET_assert (NULL != extensions); 2510 /* Fill in the configurations of the enabled extensions */ 2511 for (const struct TALER_Extensions *iter = TALER_extensions_get_head (); 2512 NULL != iter && NULL != iter->extension; 2513 iter = iter->next) 2514 { 2515 const struct TALER_Extension *extension = iter->extension; 2516 json_t *manifest; 2517 int r; 2518 2519 /* skip if not enabled */ 2520 if (! extension->enabled) 2521 continue; 2522 2523 /* flag our findings so far */ 2524 has_extensions = true; 2525 2526 2527 manifest = extension->manifest (extension); 2528 GNUNET_assert (manifest); 2529 2530 r = json_object_set_new ( 2531 extensions, 2532 extension->name, 2533 manifest); 2534 GNUNET_assert (0 == r); 2535 } 2536 2537 /* Update the keys object with the extensions and its signature */ 2538 if (has_extensions) 2539 { 2540 json_t *sig; 2541 int r; 2542 2543 r = json_object_set_new ( 2544 keys, 2545 "extensions", 2546 extensions); 2547 GNUNET_assert (0 == r); 2548 2549 /* Add the signature of the extensions, if it is not zero */ 2550 if (TEH_extensions_signed) 2551 { 2552 sig = GNUNET_JSON_PACK ( 2553 GNUNET_JSON_pack_data_auto ("extensions_sig", 2554 &TEH_extensions_sig)); 2555 2556 r = json_object_update (keys, sig); 2557 GNUNET_assert (0 == r); 2558 } 2559 } 2560 else 2561 { 2562 json_decref (extensions); 2563 } 2564 } 2565 2566 2567 { 2568 char *keys_json; 2569 void *keys_jsonz; 2570 size_t keys_jsonz_size; 2571 int comp; 2572 char etag[sizeof (struct GNUNET_HashCode) * 2]; 2573 2574 /* Convert /keys response to UTF8-String */ 2575 keys_json = json_dumps (keys, 2576 JSON_INDENT (2)); 2577 json_decref (keys); 2578 GNUNET_assert (NULL != keys_json); 2579 2580 /* Keep copy for later compression... */ 2581 keys_jsonz = GNUNET_strdup (keys_json); 2582 keys_jsonz_size = strlen (keys_json); 2583 2584 /* hash to compute etag */ 2585 { 2586 struct GNUNET_HashCode ehash; 2587 char *end; 2588 2589 GNUNET_CRYPTO_hash (keys_jsonz, 2590 keys_jsonz_size, 2591 &ehash); 2592 end = GNUNET_STRINGS_data_to_string (&ehash, 2593 sizeof (ehash), 2594 etag, 2595 sizeof (etag)); 2596 *end = '\0'; 2597 } 2598 2599 /* Create uncompressed response */ 2600 krd.response_uncompressed 2601 = MHD_create_response_from_buffer (keys_jsonz_size, 2602 keys_json, 2603 MHD_RESPMEM_MUST_FREE); 2604 GNUNET_assert (NULL != krd.response_uncompressed); 2605 setup_general_response_headers (ksh, 2606 krd.response_uncompressed); 2607 /* Information is always public, revalidate after 1 day */ 2608 GNUNET_break (MHD_YES == 2609 MHD_add_response_header (krd.response_uncompressed, 2610 MHD_HTTP_HEADER_ETAG, 2611 etag)); 2612 /* Also compute compressed version of /keys response */ 2613 comp = TALER_MHD_body_compress (&keys_jsonz, 2614 &keys_jsonz_size); 2615 krd.response_compressed 2616 = MHD_create_response_from_buffer (keys_jsonz_size, 2617 keys_jsonz, 2618 MHD_RESPMEM_MUST_FREE); 2619 GNUNET_assert (NULL != krd.response_compressed); 2620 /* If the response is actually compressed, set the 2621 respective header. */ 2622 GNUNET_assert ( (MHD_YES != comp) || 2623 (MHD_YES == 2624 MHD_add_response_header (krd.response_compressed, 2625 MHD_HTTP_HEADER_CONTENT_ENCODING, 2626 "deflate")) ); 2627 setup_general_response_headers (ksh, 2628 krd.response_compressed); 2629 /* Information is always public, revalidate after 1 day */ 2630 GNUNET_break (MHD_YES == 2631 MHD_add_response_header (krd.response_compressed, 2632 MHD_HTTP_HEADER_ETAG, 2633 etag)); 2634 krd.etag = GNUNET_strdup (etag); 2635 } 2636 krd.cherry_pick_date = last_cherry_pick_date; 2637 GNUNET_array_append (ksh->krd_array, 2638 ksh->krd_array_length, 2639 krd); 2640 return GNUNET_OK; 2641 } 2642 2643 2644 /** 2645 * Element in the `struct SignatureContext` array. 2646 */ 2647 struct SignatureElement 2648 { 2649 2650 /** 2651 * Offset of the denomination in the group array, 2652 * for sorting (2nd rank, ascending). 2653 */ 2654 unsigned int offset; 2655 2656 /** 2657 * Offset of the group in the denominations array, 2658 * for sorting (2nd rank, ascending). 2659 */ 2660 unsigned int group_offset; 2661 2662 /** 2663 * Pointer to actual master signature to hash over. 2664 */ 2665 struct TALER_MasterSignatureP master_sig; 2666 }; 2667 2668 /** 2669 * Context for collecting the array of master signatures 2670 * needed to verify the exchange_sig online signature. 2671 */ 2672 struct SignatureContext 2673 { 2674 /** 2675 * Array of signatures to hash over. 2676 */ 2677 struct SignatureElement *elements; 2678 2679 /** 2680 * Write offset in the @e elements array. 2681 */ 2682 unsigned int elements_pos; 2683 2684 /** 2685 * Allocated space for @e elements. 2686 */ 2687 unsigned int elements_size; 2688 }; 2689 2690 2691 /** 2692 * Determine order to sort two elements by before 2693 * we hash the master signatures. Used for 2694 * sorting with qsort(). 2695 * 2696 * @param a pointer to a `struct SignatureElement` 2697 * @param b pointer to a `struct SignatureElement` 2698 * @return 0 if equal, -1 if a < b, 1 if a > b. 2699 */ 2700 static int 2701 signature_context_sort_cb (const void *a, 2702 const void *b) 2703 { 2704 const struct SignatureElement *sa = a; 2705 const struct SignatureElement *sb = b; 2706 2707 if (sa->group_offset < sb->group_offset) 2708 return -1; 2709 if (sa->group_offset > sb->group_offset) 2710 return 1; 2711 if (sa->offset < sb->offset) 2712 return -1; 2713 if (sa->offset > sb->offset) 2714 return 1; 2715 /* We should never have two disjoint elements 2716 with same time and offset */ 2717 GNUNET_assert (sa == sb); 2718 return 0; 2719 } 2720 2721 2722 /** 2723 * Append a @a master_sig to the @a sig_ctx using the 2724 * given attributes for (later) sorting. 2725 * 2726 * @param[in,out] sig_ctx signature context to update 2727 * @param group_offset offset for the group 2728 * @param offset offset for the entry 2729 * @param master_sig master signature for the entry 2730 */ 2731 static void 2732 append_signature (struct SignatureContext *sig_ctx, 2733 unsigned int group_offset, 2734 unsigned int offset, 2735 const struct TALER_MasterSignatureP *master_sig) 2736 { 2737 struct SignatureElement *element; 2738 unsigned int new_size; 2739 2740 if (sig_ctx->elements_pos == sig_ctx->elements_size) 2741 { 2742 if (0 == sig_ctx->elements_size) 2743 new_size = 1024; 2744 else 2745 new_size = sig_ctx->elements_size * 2; 2746 GNUNET_array_grow (sig_ctx->elements, 2747 sig_ctx->elements_size, 2748 new_size); 2749 } 2750 element = &sig_ctx->elements[sig_ctx->elements_pos++]; 2751 element->offset = offset; 2752 element->group_offset = group_offset; 2753 element->master_sig = *master_sig; 2754 } 2755 2756 2757 /** 2758 *GroupData is the value we store for each group meta-data */ 2759 struct GroupData 2760 { 2761 /** 2762 * The json blob with the group meta-data and list of denominations 2763 */ 2764 json_t *json; 2765 2766 /** 2767 * List of denominations for the group, 2768 * included in @e json, do not free separately! 2769 */ 2770 json_t *list; 2771 2772 /** 2773 * Offset of the group in the final array. 2774 */ 2775 unsigned int group_off; 2776 2777 }; 2778 2779 2780 /** 2781 * Helper function called to clean up the group data 2782 * in the denominations_by_group below. 2783 * 2784 * @param cls unused 2785 * @param key unused 2786 * @param value a `struct GroupData` to free 2787 * @return #GNUNET_OK 2788 */ 2789 static int 2790 free_group (void *cls, 2791 const struct GNUNET_HashCode *key, 2792 void *value) 2793 { 2794 struct GroupData *gd = value; 2795 2796 (void) cls; 2797 (void) key; 2798 GNUNET_free (gd); 2799 return GNUNET_OK; 2800 } 2801 2802 2803 static void 2804 compute_msig_hash (struct SignatureContext *sig_ctx, 2805 struct GNUNET_HashCode *hc) 2806 { 2807 struct GNUNET_HashContext *hash_context; 2808 2809 hash_context = GNUNET_CRYPTO_hash_context_start (); 2810 qsort (sig_ctx->elements, 2811 sig_ctx->elements_pos, 2812 sizeof (struct SignatureElement), 2813 &signature_context_sort_cb); 2814 for (unsigned int i = 0; i<sig_ctx->elements_pos; i++) 2815 { 2816 struct SignatureElement *element = &sig_ctx->elements[i]; 2817 2818 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 2819 "Adding %u,%u,%s\n", 2820 element->group_offset, 2821 element->offset, 2822 TALER_B2S (&element->master_sig)); 2823 GNUNET_CRYPTO_hash_context_read (hash_context, 2824 &element->master_sig, 2825 sizeof (element->master_sig)); 2826 } 2827 GNUNET_CRYPTO_hash_context_finish (hash_context, 2828 hc); 2829 } 2830 2831 2832 /** 2833 * Update the "/keys" responses in @a ksh, computing the detailed replies. 2834 * 2835 * This function is to recompute all (including cherry-picked) responses we 2836 * might want to return, based on the state already in @a ksh. 2837 * 2838 * @param[in,out] ksh state handle to update 2839 * @return #GNUNET_OK on success 2840 */ 2841 static enum GNUNET_GenericReturnValue 2842 finish_keys_response (struct TEH_KeyStateHandle *ksh) 2843 { 2844 enum GNUNET_GenericReturnValue ret = GNUNET_SYSERR; 2845 json_t *recoup; 2846 struct SignKeyCtx sctx = { 2847 .min_sk_frequency = GNUNET_TIME_UNIT_FOREVER_REL 2848 }; 2849 json_t *grouped_denominations = NULL; 2850 struct GNUNET_TIME_Timestamp last_cherry_pick_date; 2851 struct GNUNET_CONTAINER_Heap *heap; 2852 struct SignatureContext sig_ctx = { 0 }; 2853 /* Remember if we have any denomination with age restriction */ 2854 bool has_age_restricted_denomination = false; 2855 struct WireStateHandle *wsh; 2856 2857 wsh = get_wire_state (); 2858 if (! wsh->ready) 2859 { 2860 GNUNET_break (0); 2861 return GNUNET_SYSERR; 2862 } 2863 if (0 == 2864 json_array_size (json_object_get (wsh->json_reply, 2865 "accounts")) ) 2866 { 2867 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 2868 "No wire accounts available. Refusing to generate /keys response.\n"); 2869 return GNUNET_NO; 2870 } 2871 sctx.signkeys = json_array (); 2872 GNUNET_assert (NULL != sctx.signkeys); 2873 recoup = json_array (); 2874 GNUNET_assert (NULL != recoup); 2875 grouped_denominations = json_array (); 2876 GNUNET_assert (NULL != grouped_denominations); 2877 2878 GNUNET_CONTAINER_multipeermap_iterate (ksh->signkey_map, 2879 &add_sign_key_cb, 2880 &sctx); 2881 if (0 == json_array_size (sctx.signkeys)) 2882 { 2883 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 2884 "No online signing keys available. Refusing to generate /keys response.\n"); 2885 ret = GNUNET_NO; 2886 goto CLEANUP; 2887 } 2888 heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MAX); 2889 { 2890 struct DenomKeyCtx dkc = { 2891 .recoup = recoup, 2892 .heap = heap, 2893 .min_dk_frequency = GNUNET_TIME_UNIT_FOREVER_REL, 2894 }; 2895 2896 GNUNET_CONTAINER_multihashmap_iterate (ksh->denomkey_map, 2897 &add_denom_key_cb, 2898 &dkc); 2899 ksh->rekey_frequency 2900 = GNUNET_TIME_relative_min (dkc.min_dk_frequency, 2901 sctx.min_sk_frequency); 2902 } 2903 2904 last_cherry_pick_date = GNUNET_TIME_UNIT_ZERO_TS; 2905 2906 { 2907 struct TEH_DenominationKey *dk; 2908 struct GNUNET_CONTAINER_MultiHashMap *denominations_by_group; 2909 2910 denominations_by_group = 2911 GNUNET_CONTAINER_multihashmap_create (1024, 2912 GNUNET_NO /* NO, because keys are only on the stack */ 2913 ); 2914 /* heap = max heap, sorted by start time */ 2915 while (NULL != (dk = GNUNET_CONTAINER_heap_remove_root (heap))) 2916 { 2917 if (GNUNET_TIME_timestamp_cmp (last_cherry_pick_date, 2918 !=, 2919 dk->meta.start) && 2920 (! GNUNET_TIME_absolute_is_zero (last_cherry_pick_date.abs_time)) ) 2921 { 2922 /* 2923 * This is not the first entry in the heap (because last_cherry_pick_date != 2924 * GNUNET_TIME_UNIT_ZERO_TS) and the previous entry had a different 2925 * start time. Therefore, we create a new entry in ksh. 2926 */ 2927 struct GNUNET_HashCode hc; 2928 2929 compute_msig_hash (&sig_ctx, 2930 &hc); 2931 if (GNUNET_OK != 2932 create_krd (ksh, 2933 &hc, 2934 last_cherry_pick_date, 2935 sctx.signkeys, 2936 recoup, 2937 grouped_denominations)) 2938 { 2939 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 2940 "Failed to generate key response data for %s\n", 2941 GNUNET_TIME_timestamp2s (last_cherry_pick_date)); 2942 /* drain heap before destroying it */ 2943 while (NULL != (dk = GNUNET_CONTAINER_heap_remove_root (heap))) 2944 /* intentionally empty */; 2945 GNUNET_CONTAINER_heap_destroy (heap); 2946 goto CLEANUP; 2947 } 2948 } 2949 2950 last_cherry_pick_date = dk->meta.start; 2951 /* 2952 * Group the denominations by {cipher, value, fees, age_mask}. 2953 * 2954 * For each group we save the group meta-data and the list of 2955 * denominations in this group as a json-blob in the multihashmap 2956 * denominations_by_group. 2957 */ 2958 { 2959 struct GroupData *group; 2960 json_t *entry; 2961 struct GNUNET_HashCode key; 2962 struct TALER_DenominationGroup meta = { 2963 .cipher = dk->denom_pub.bsign_pub_key->cipher, 2964 .value = dk->meta.value, 2965 .fees = dk->meta.fees, 2966 .age_mask = dk->meta.age_mask, 2967 }; 2968 2969 /* Search the group/JSON-blob for the key */ 2970 TALER_denomination_group_get_key (&meta, 2971 &key); 2972 group = GNUNET_CONTAINER_multihashmap_get ( 2973 denominations_by_group, 2974 &key); 2975 if (NULL == group) 2976 { 2977 /* There is no group for this meta-data yet, so we create a new group */ 2978 bool age_restricted = meta.age_mask.bits != 0; 2979 const char *cipher; 2980 2981 group = GNUNET_new (struct GroupData); 2982 switch (meta.cipher) 2983 { 2984 case GNUNET_CRYPTO_BSA_RSA: 2985 cipher = age_restricted ? "RSA+age_restricted" : "RSA"; 2986 break; 2987 case GNUNET_CRYPTO_BSA_CS: 2988 cipher = age_restricted ? "CS+age_restricted" : "CS"; 2989 break; 2990 default: 2991 GNUNET_assert (false); 2992 } 2993 /* Create a new array for the denominations in this group */ 2994 group->list = json_array (); 2995 GNUNET_assert (NULL != group->list); 2996 group->json = GNUNET_JSON_PACK ( 2997 GNUNET_JSON_pack_string ("cipher", 2998 cipher), 2999 GNUNET_JSON_pack_array_steal ("denoms", 3000 group->list), 3001 TALER_JSON_PACK_DENOM_FEES ("fee", 3002 &meta.fees), 3003 TALER_JSON_pack_amount ("value", 3004 &meta.value)); 3005 GNUNET_assert (NULL != group->json); 3006 if (age_restricted) 3007 { 3008 GNUNET_assert ( 3009 0 == 3010 json_object_set_new (group->json, 3011 "age_mask", 3012 json_integer ( 3013 meta.age_mask.bits))); 3014 /* Remember that we have found at least _one_ age restricted denomination */ 3015 has_age_restricted_denomination = true; 3016 } 3017 group->group_off 3018 = json_array_size (grouped_denominations); 3019 GNUNET_assert (0 == 3020 json_array_append_new ( 3021 grouped_denominations, 3022 group->json)); 3023 GNUNET_assert ( 3024 GNUNET_OK == 3025 GNUNET_CONTAINER_multihashmap_put (denominations_by_group, 3026 &key, 3027 group, 3028 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); 3029 } 3030 3031 /* Now that we have found/created the right group, add the 3032 denomination to the list */ 3033 { 3034 struct HelperDenomination *hd; 3035 struct GNUNET_JSON_PackSpec key_spec; 3036 bool private_key_lost; 3037 3038 hd = GNUNET_CONTAINER_multihashmap_get (helpers.denom_keys, 3039 &dk->h_denom_pub.hash); 3040 private_key_lost 3041 = (NULL == hd) || 3042 GNUNET_TIME_absolute_is_past ( 3043 GNUNET_TIME_absolute_add ( 3044 hd->start_time.abs_time, 3045 hd->validity_duration)); 3046 switch (meta.cipher) 3047 { 3048 case GNUNET_CRYPTO_BSA_RSA: 3049 key_spec = 3050 GNUNET_JSON_pack_rsa_public_key ( 3051 "rsa_pub", 3052 dk->denom_pub.bsign_pub_key->details.rsa_public_key); 3053 break; 3054 case GNUNET_CRYPTO_BSA_CS: 3055 key_spec = 3056 GNUNET_JSON_pack_data_varsize ( 3057 "cs_pub", 3058 &dk->denom_pub.bsign_pub_key->details.cs_public_key, 3059 sizeof (dk->denom_pub.bsign_pub_key->details.cs_public_key)); 3060 break; 3061 default: 3062 GNUNET_assert (false); 3063 } 3064 3065 entry = GNUNET_JSON_PACK ( 3066 GNUNET_JSON_pack_data_auto ("master_sig", 3067 &dk->master_sig), 3068 GNUNET_JSON_pack_allow_null ( 3069 private_key_lost 3070 ? GNUNET_JSON_pack_bool ("lost", 3071 true) 3072 : GNUNET_JSON_pack_string ("dummy", 3073 NULL)), 3074 GNUNET_JSON_pack_timestamp ("stamp_start", 3075 dk->meta.start), 3076 GNUNET_JSON_pack_timestamp ("stamp_expire_withdraw", 3077 dk->meta.expire_withdraw), 3078 GNUNET_JSON_pack_timestamp ("stamp_expire_deposit", 3079 dk->meta.expire_deposit), 3080 GNUNET_JSON_pack_timestamp ("stamp_expire_legal", 3081 dk->meta.expire_legal), 3082 key_spec 3083 ); 3084 GNUNET_assert (NULL != entry); 3085 } 3086 3087 /* Build up the running hash of all master signatures of the 3088 denominations */ 3089 append_signature (&sig_ctx, 3090 group->group_off, 3091 (unsigned int) json_array_size (group->list), 3092 &dk->master_sig); 3093 /* Finally, add the denomination to the list of denominations in this 3094 group */ 3095 GNUNET_assert (json_is_array (group->list)); 3096 GNUNET_assert (0 == 3097 json_array_append_new (group->list, 3098 entry)); 3099 } 3100 } /* loop over heap ends */ 3101 3102 GNUNET_CONTAINER_multihashmap_iterate (denominations_by_group, 3103 &free_group, 3104 NULL); 3105 GNUNET_CONTAINER_multihashmap_destroy (denominations_by_group); 3106 } 3107 GNUNET_CONTAINER_heap_destroy (heap); 3108 3109 if (! GNUNET_TIME_absolute_is_zero (last_cherry_pick_date.abs_time)) 3110 { 3111 struct GNUNET_HashCode hc; 3112 3113 compute_msig_hash (&sig_ctx, 3114 &hc); 3115 if (GNUNET_OK != 3116 create_krd (ksh, 3117 &hc, 3118 last_cherry_pick_date, 3119 sctx.signkeys, 3120 recoup, 3121 grouped_denominations)) 3122 { 3123 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 3124 "Failed to generate key response data for %s\n", 3125 GNUNET_TIME_timestamp2s (last_cherry_pick_date)); 3126 goto CLEANUP; 3127 } 3128 ksh->management_only = false; 3129 3130 /* Sanity check: Make sure that age restriction is enabled IFF at least 3131 * one age restricted denomination exist */ 3132 if (! has_age_restricted_denomination && TEH_age_restriction_enabled) 3133 { 3134 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 3135 "Age restriction is enabled, but NO denominations with age restriction found!\n"); 3136 goto CLEANUP; 3137 } 3138 else if (has_age_restricted_denomination && ! TEH_age_restriction_enabled) 3139 { 3140 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 3141 "Age restriction is NOT enabled, but denominations with age restriction found!\n") 3142 ; 3143 goto CLEANUP; 3144 } 3145 } 3146 else 3147 { 3148 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 3149 "No denomination keys available. Refusing to generate /keys response.\n"); 3150 } 3151 ret = GNUNET_OK; 3152 3153 CLEANUP: 3154 GNUNET_array_grow (sig_ctx.elements, 3155 sig_ctx.elements_size, 3156 0); 3157 json_decref (grouped_denominations); 3158 if (NULL != sctx.signkeys) 3159 json_decref (sctx.signkeys); 3160 json_decref (recoup); 3161 return ret; 3162 } 3163 3164 3165 /** 3166 * Called with information about global fees. 3167 * 3168 * @param cls `struct TEH_KeyStateHandle *` we are building 3169 * @param fees the global fees we charge 3170 * @param purse_timeout when do purses time out 3171 * @param history_expiration how long are account histories preserved 3172 * @param purse_account_limit how many purses are free per account 3173 * @param start_date from when are these fees valid (start date) 3174 * @param end_date until when are these fees valid (end date, exclusive) 3175 * @param master_sig master key signature affirming that this is the correct 3176 * fee (of purpose #TALER_SIGNATURE_MASTER_GLOBAL_FEES) 3177 */ 3178 static void 3179 global_fee_info_cb ( 3180 void *cls, 3181 const struct TALER_GlobalFeeSet *fees, 3182 struct GNUNET_TIME_Relative purse_timeout, 3183 struct GNUNET_TIME_Relative history_expiration, 3184 uint32_t purse_account_limit, 3185 struct GNUNET_TIME_Timestamp start_date, 3186 struct GNUNET_TIME_Timestamp end_date, 3187 const struct TALER_MasterSignatureP *master_sig) 3188 { 3189 struct TEH_KeyStateHandle *ksh = cls; 3190 struct TEH_GlobalFee *gf; 3191 3192 if (GNUNET_OK != 3193 TALER_exchange_offline_global_fee_verify ( 3194 start_date, 3195 end_date, 3196 fees, 3197 purse_timeout, 3198 history_expiration, 3199 purse_account_limit, 3200 &TEH_master_public_key, 3201 master_sig)) 3202 { 3203 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 3204 "Database has global fee with invalid signature. Skipping entry. Did the exchange offline public key change?\n"); 3205 return; 3206 } 3207 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 3208 "Found global fees with %u purses\n", 3209 purse_account_limit); 3210 gf = GNUNET_new (struct TEH_GlobalFee); 3211 gf->start_date = start_date; 3212 gf->end_date = end_date; 3213 gf->fees = *fees; 3214 gf->purse_timeout = purse_timeout; 3215 gf->history_expiration = history_expiration; 3216 gf->purse_account_limit = purse_account_limit; 3217 gf->master_sig = *master_sig; 3218 GNUNET_CONTAINER_DLL_insert (ksh->gf_head, 3219 ksh->gf_tail, 3220 gf); 3221 GNUNET_assert ( 3222 0 == 3223 json_array_append_new ( 3224 ksh->global_fees, 3225 GNUNET_JSON_PACK ( 3226 GNUNET_JSON_pack_timestamp ("start_date", 3227 start_date), 3228 GNUNET_JSON_pack_timestamp ("end_date", 3229 end_date), 3230 TALER_JSON_PACK_GLOBAL_FEES (fees), 3231 GNUNET_JSON_pack_time_rel ("history_expiration", 3232 history_expiration), 3233 GNUNET_JSON_pack_time_rel ("purse_timeout", 3234 purse_timeout), 3235 GNUNET_JSON_pack_uint64 ("purse_account_limit", 3236 purse_account_limit), 3237 GNUNET_JSON_pack_data_auto ("master_sig", 3238 master_sig)))); 3239 } 3240 3241 3242 /** 3243 * Create a key state. 3244 * 3245 * @param management_only if we should NOT run 'finish_keys_response()' 3246 * because we only need the state for the /management/keys API 3247 * @return NULL on error (i.e. failed to access database) 3248 */ 3249 static struct TEH_KeyStateHandle * 3250 build_key_state (bool management_only) 3251 { 3252 struct TEH_KeyStateHandle *ksh; 3253 enum GNUNET_DB_QueryStatus qs; 3254 3255 ksh = GNUNET_new (struct TEH_KeyStateHandle); 3256 ksh->signature_expires = GNUNET_TIME_UNIT_FOREVER_TS; 3257 ksh->reload_time = GNUNET_TIME_timestamp_get (); 3258 /* We must use the key_generation from when we STARTED the process! */ 3259 ksh->key_generation = key_generation; 3260 ksh->denomserial_map = GNUNET_CONTAINER_multihashmap32_create (1024); 3261 ksh->denomkey_map = GNUNET_CONTAINER_multihashmap_create (1024, 3262 true); 3263 ksh->signkey_map = GNUNET_CONTAINER_multipeermap_create (32, 3264 false /* MUST be false! */ 3265 ); 3266 ksh->auditors = json_array (); 3267 GNUNET_assert (NULL != ksh->auditors); 3268 /* NOTE: fetches master-signed signkeys, but ALSO those that were revoked! */ 3269 GNUNET_break (GNUNET_OK == 3270 TEH_plugin->preflight (TEH_plugin->cls)); 3271 if (NULL != ksh->global_fees) 3272 json_decref (ksh->global_fees); 3273 ksh->global_fees = json_array (); 3274 qs = TEH_plugin->get_global_fees (TEH_plugin->cls, 3275 &global_fee_info_cb, 3276 ksh); 3277 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 3278 "Loading global fees from DB: %d\n", 3279 qs); 3280 if (qs < 0) 3281 { 3282 GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs); 3283 GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR != qs); 3284 destroy_key_state (ksh); 3285 return NULL; 3286 } 3287 qs = TEH_plugin->iterate_denominations (TEH_plugin->cls, 3288 &denomination_info_cb, 3289 ksh); 3290 if (qs < 0) 3291 { 3292 GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs); 3293 GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR != qs); 3294 destroy_key_state (ksh); 3295 return NULL; 3296 } 3297 /* NOTE: ONLY fetches non-revoked AND master-signed signkeys! */ 3298 qs = TEH_plugin->iterate_active_signkeys (TEH_plugin->cls, 3299 &signkey_info_cb, 3300 ksh); 3301 if (qs < 0) 3302 { 3303 GNUNET_break (0); 3304 destroy_key_state (ksh); 3305 return NULL; 3306 } 3307 qs = TEH_plugin->iterate_auditor_denominations (TEH_plugin->cls, 3308 &auditor_denom_cb, 3309 ksh); 3310 if (qs < 0) 3311 { 3312 GNUNET_break (0); 3313 destroy_key_state (ksh); 3314 return NULL; 3315 } 3316 qs = TEH_plugin->iterate_active_auditors (TEH_plugin->cls, 3317 &auditor_info_cb, 3318 ksh); 3319 if (qs < 0) 3320 { 3321 GNUNET_break (0); 3322 destroy_key_state (ksh); 3323 return NULL; 3324 } 3325 3326 if (management_only) 3327 { 3328 ksh->management_only = true; 3329 return ksh; 3330 } 3331 3332 if (GNUNET_OK != 3333 finish_keys_response (ksh)) 3334 { 3335 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 3336 "Could not finish /keys response (required data not configured yet)\n"); 3337 destroy_key_state (ksh); 3338 return NULL; 3339 } 3340 TEH_resume_keys_requests (false); 3341 return ksh; 3342 } 3343 3344 3345 void 3346 TEH_keys_update_states () 3347 { 3348 struct GNUNET_DB_EventHeaderP es = { 3349 .size = htons (sizeof (es)), 3350 .type = htons (TALER_DBEVENT_EXCHANGE_KEYS_UPDATED), 3351 }; 3352 3353 TEH_plugin->event_notify (TEH_plugin->cls, 3354 &es, 3355 NULL, 3356 0); 3357 key_generation++; 3358 TEH_resume_keys_requests (false); 3359 } 3360 3361 3362 static struct TEH_KeyStateHandle * 3363 keys_get_state (bool management_only) 3364 { 3365 struct TEH_KeyStateHandle *old_ksh; 3366 struct TEH_KeyStateHandle *ksh; 3367 3368 old_ksh = key_state; 3369 if (NULL == old_ksh) 3370 { 3371 ksh = build_key_state (management_only); 3372 if (NULL == ksh) 3373 return NULL; 3374 key_state = ksh; 3375 return ksh; 3376 } 3377 if ( (old_ksh->key_generation < key_generation) || 3378 (GNUNET_TIME_absolute_is_past (old_ksh->signature_expires.abs_time)) ) 3379 { 3380 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 3381 "Rebuilding /keys, generation upgrade from %llu to %llu\n", 3382 (unsigned long long) old_ksh->key_generation, 3383 (unsigned long long) key_generation); 3384 ksh = build_key_state (management_only); 3385 key_state = ksh; 3386 destroy_key_state (old_ksh); 3387 return ksh; 3388 } 3389 sync_key_helpers (&helpers); 3390 return old_ksh; 3391 } 3392 3393 3394 struct TEH_KeyStateHandle * 3395 TEH_keys_get_state_for_management_only (void) 3396 { 3397 return keys_get_state (true); 3398 } 3399 3400 3401 struct TEH_KeyStateHandle * 3402 TEH_keys_get_state (void) 3403 { 3404 struct TEH_KeyStateHandle *ksh; 3405 3406 ksh = keys_get_state (false); 3407 if (NULL == ksh) 3408 return NULL; 3409 3410 if (ksh->management_only) 3411 { 3412 if (GNUNET_OK != 3413 finish_keys_response (ksh)) 3414 return NULL; 3415 } 3416 3417 return ksh; 3418 } 3419 3420 3421 const struct TEH_GlobalFee * 3422 TEH_keys_global_fee_by_time ( 3423 struct TEH_KeyStateHandle *ksh, 3424 struct GNUNET_TIME_Timestamp ts) 3425 { 3426 for (const struct TEH_GlobalFee *gf = ksh->gf_head; 3427 NULL != gf; 3428 gf = gf->next) 3429 { 3430 if (GNUNET_TIME_timestamp_cmp (ts, 3431 >=, 3432 gf->start_date) && 3433 GNUNET_TIME_timestamp_cmp (ts, 3434 <, 3435 gf->end_date)) 3436 return gf; 3437 } 3438 return NULL; 3439 } 3440 3441 3442 struct TEH_DenominationKey * 3443 TEH_keys_denomination_by_hash ( 3444 const struct TALER_DenominationHashP *h_denom_pub, 3445 struct MHD_Connection *conn, 3446 MHD_RESULT *mret) 3447 { 3448 struct TEH_KeyStateHandle *ksh; 3449 3450 ksh = TEH_keys_get_state (); 3451 if (NULL == ksh) 3452 { 3453 *mret = TALER_MHD_reply_with_error (conn, 3454 MHD_HTTP_INTERNAL_SERVER_ERROR, 3455 TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING, 3456 NULL); 3457 return NULL; 3458 } 3459 3460 return TEH_keys_denomination_by_hash_from_state (ksh, 3461 h_denom_pub, 3462 conn, 3463 mret); 3464 } 3465 3466 3467 struct TEH_DenominationKey * 3468 TEH_keys_denomination_by_hash_from_state ( 3469 const struct TEH_KeyStateHandle *ksh, 3470 const struct TALER_DenominationHashP *h_denom_pub, 3471 struct MHD_Connection *conn, 3472 MHD_RESULT *mret) 3473 { 3474 struct TEH_DenominationKey *dk; 3475 3476 dk = GNUNET_CONTAINER_multihashmap_get (ksh->denomkey_map, 3477 &h_denom_pub->hash); 3478 if (NULL == dk) 3479 { 3480 if (NULL == conn) 3481 return NULL; 3482 *mret = TEH_RESPONSE_reply_unknown_denom_pub_hash (conn, 3483 h_denom_pub); 3484 return NULL; 3485 } 3486 return dk; 3487 } 3488 3489 3490 struct TEH_DenominationKey * 3491 TEH_keys_denomination_by_serial_from_state ( 3492 const struct TEH_KeyStateHandle *ksh, 3493 uint64_t denom_serial) 3494 { 3495 struct TEH_DenominationKey *dk; 3496 uint32_t serial32 = (uint32_t) denom_serial; 3497 3498 GNUNET_assert (denom_serial == (uint64_t) serial32); 3499 dk = GNUNET_CONTAINER_multihashmap32_get (ksh->denomserial_map, 3500 serial32); 3501 return dk; 3502 } 3503 3504 3505 enum TALER_ErrorCode 3506 TEH_keys_denomination_batch_sign ( 3507 unsigned int csds_length, 3508 const struct TEH_CoinSignData csds[static csds_length], 3509 bool for_melt, 3510 struct TALER_BlindedDenominationSignature bss[static csds_length]) 3511 { 3512 struct TEH_KeyStateHandle *ksh; 3513 struct HelperDenomination *hd; 3514 struct TALER_CRYPTO_RsaSignRequest rsrs[csds_length]; 3515 struct TALER_CRYPTO_CsSignRequest csrs[csds_length]; 3516 struct TALER_BlindedDenominationSignature rs[csds_length]; 3517 struct TALER_BlindedDenominationSignature cs[csds_length]; 3518 unsigned int rsrs_pos = 0; 3519 unsigned int csrs_pos = 0; 3520 enum TALER_ErrorCode ec; 3521 3522 ksh = TEH_keys_get_state (); 3523 if (NULL == ksh) 3524 return TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING; 3525 for (unsigned int i = 0; i<csds_length; i++) 3526 { 3527 const struct TALER_DenominationHashP *h_denom_pub = csds[i].h_denom_pub; 3528 const struct TALER_BlindedPlanchet *bp = csds[i].bp; 3529 3530 hd = GNUNET_CONTAINER_multihashmap_get (helpers.denom_keys, 3531 &h_denom_pub->hash); 3532 if (NULL == hd) 3533 return TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN; 3534 if (bp->blinded_message->cipher != 3535 hd->denom_pub.bsign_pub_key->cipher) 3536 return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; 3537 switch (hd->denom_pub.bsign_pub_key->cipher) 3538 { 3539 case GNUNET_CRYPTO_BSA_RSA: 3540 rsrs[rsrs_pos].h_rsa = &hd->h_details.h_rsa; 3541 rsrs[rsrs_pos].msg 3542 = bp->blinded_message->details.rsa_blinded_message.blinded_msg; 3543 rsrs[rsrs_pos].msg_size 3544 = bp->blinded_message->details.rsa_blinded_message.blinded_msg_size; 3545 rsrs_pos++; 3546 break; 3547 case GNUNET_CRYPTO_BSA_CS: 3548 csrs[csrs_pos].h_cs = &hd->h_details.h_cs; 3549 csrs[csrs_pos].blinded_planchet 3550 = &bp->blinded_message->details.cs_blinded_message; 3551 csrs_pos++; 3552 break; 3553 default: 3554 return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; 3555 } 3556 } 3557 3558 if (0 != rsrs_pos) 3559 { 3560 memset (rs, 3561 0, 3562 sizeof (rs)); 3563 } 3564 if (0 != csrs_pos) 3565 { 3566 memset (cs, 3567 0, 3568 sizeof (cs)); 3569 } 3570 ec = TALER_EC_NONE; 3571 if (0 != csrs_pos) 3572 { 3573 ec = TALER_CRYPTO_helper_cs_batch_sign ( 3574 helpers.csdh, 3575 csrs_pos, 3576 csrs, 3577 for_melt, 3578 (0 == rsrs_pos) ? bss : cs); 3579 if (TALER_EC_NONE != ec) 3580 { 3581 for (unsigned int i = 0; i<csrs_pos; i++) 3582 TALER_blinded_denom_sig_free (&cs[i]); 3583 return ec; 3584 } 3585 TEH_METRICS_num_signatures[TEH_MT_SIGNATURE_CS] += csrs_pos; 3586 } 3587 if (0 != rsrs_pos) 3588 { 3589 ec = TALER_CRYPTO_helper_rsa_batch_sign ( 3590 helpers.rsadh, 3591 rsrs_pos, 3592 rsrs, 3593 (0 == csrs_pos) ? bss : rs); 3594 if (TALER_EC_NONE != ec) 3595 { 3596 for (unsigned int i = 0; i<csrs_pos; i++) 3597 TALER_blinded_denom_sig_free (&cs[i]); 3598 for (unsigned int i = 0; i<rsrs_pos; i++) 3599 TALER_blinded_denom_sig_free (&rs[i]); 3600 return ec; 3601 } 3602 TEH_METRICS_num_signatures[TEH_MT_SIGNATURE_RSA] += rsrs_pos; 3603 } 3604 3605 if ( (0 != csrs_pos) && 3606 (0 != rsrs_pos) ) 3607 { 3608 rsrs_pos = 0; 3609 csrs_pos = 0; 3610 for (unsigned int i = 0; i<csds_length; i++) 3611 { 3612 const struct TALER_BlindedPlanchet *bp = csds[i].bp; 3613 3614 switch (bp->blinded_message->cipher) 3615 { 3616 case GNUNET_CRYPTO_BSA_RSA: 3617 bss[i] = rs[rsrs_pos++]; 3618 break; 3619 case GNUNET_CRYPTO_BSA_CS: 3620 bss[i] = cs[csrs_pos++]; 3621 break; 3622 default: 3623 GNUNET_assert (0); 3624 } 3625 } 3626 } 3627 return TALER_EC_NONE; 3628 } 3629 3630 3631 enum TALER_ErrorCode 3632 TEH_keys_denomination_cs_r_pub ( 3633 const struct TEH_CsDeriveData *cdd, 3634 bool for_melt, 3635 struct GNUNET_CRYPTO_CSPublicRPairP *r_pub) 3636 { 3637 const struct TALER_DenominationHashP *h_denom_pub = cdd->h_denom_pub; 3638 const struct GNUNET_CRYPTO_CsSessionNonce *nonce = cdd->nonce; 3639 struct TEH_KeyStateHandle *ksh; 3640 struct HelperDenomination *hd; 3641 3642 ksh = TEH_keys_get_state (); 3643 if (NULL == ksh) 3644 { 3645 return TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING; 3646 } 3647 hd = GNUNET_CONTAINER_multihashmap_get (helpers.denom_keys, 3648 &h_denom_pub->hash); 3649 if (NULL == hd) 3650 { 3651 return TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN; 3652 } 3653 if (GNUNET_CRYPTO_BSA_CS != 3654 hd->denom_pub.bsign_pub_key->cipher) 3655 { 3656 return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; 3657 } 3658 3659 { 3660 struct TALER_CRYPTO_CsDeriveRequest cdr = { 3661 .h_cs = &hd->h_details.h_cs, 3662 .nonce = nonce 3663 }; 3664 return TALER_CRYPTO_helper_cs_r_derive (helpers.csdh, 3665 &cdr, 3666 for_melt, 3667 r_pub); 3668 } 3669 } 3670 3671 3672 enum TALER_ErrorCode 3673 TEH_keys_denomination_cs_batch_r_pub_simple ( 3674 unsigned int cdds_length, 3675 const struct TEH_CsDeriveData cdds[static cdds_length], 3676 bool for_melt, 3677 struct GNUNET_CRYPTO_CSPublicRPairP r_pubs[static cdds_length]) 3678 { 3679 struct TEH_KeyStateHandle *ksh; 3680 struct HelperDenomination *hd; 3681 struct TALER_CRYPTO_CsDeriveRequest cdrs[cdds_length]; 3682 3683 ksh = TEH_keys_get_state (); 3684 if (NULL == ksh) 3685 { 3686 return TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING; 3687 } 3688 for (unsigned int i = 0; i<cdds_length; i++) 3689 { 3690 const struct TALER_DenominationHashP *h_denom_pub = cdds[i].h_denom_pub; 3691 const struct GNUNET_CRYPTO_CsSessionNonce *nonce = cdds[i].nonce; 3692 3693 hd = GNUNET_CONTAINER_multihashmap_get (helpers.denom_keys, 3694 &h_denom_pub->hash); 3695 if (NULL == hd) 3696 { 3697 return TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN; 3698 } 3699 if (GNUNET_CRYPTO_BSA_CS != 3700 hd->denom_pub.bsign_pub_key->cipher) 3701 { 3702 return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; 3703 } 3704 cdrs[i].h_cs = &hd->h_details.h_cs; 3705 cdrs[i].nonce = nonce; 3706 } 3707 3708 return TALER_CRYPTO_helper_cs_r_batch_derive (helpers.csdh, 3709 cdds_length, 3710 cdrs, 3711 for_melt, 3712 r_pubs); 3713 } 3714 3715 3716 enum TALER_ErrorCode 3717 TEH_keys_denomination_cs_batch_r_pub ( 3718 const struct TEH_KeyStateHandle *ksh, 3719 size_t num, 3720 const struct TALER_DenominationHashP h_denom_pubs[static num], 3721 const struct GNUNET_CRYPTO_CsSessionNonce nonces[static num], 3722 bool for_melt, 3723 struct GNUNET_CRYPTO_CSPublicRPairP r_pubs[static num], 3724 size_t *err_idx) 3725 { 3726 struct TALER_CRYPTO_CsDeriveRequest cdrs[num]; 3727 3728 for (unsigned int i = 0; i<num; i++) 3729 { 3730 const struct TEH_DenominationKey *dk; 3731 const struct HelperDenomination *hd; 3732 3733 *err_idx = i; 3734 3735 /* FIXME: right now we need both, 3736 * TEH_DenominationKey and HelperDenomination, 3737 * because only TEH_DenominationKey has .recoup_possible 3738 */ 3739 hd = GNUNET_CONTAINER_multihashmap_get (helpers.denom_keys, 3740 &h_denom_pubs[i].hash); 3741 dk = TEH_keys_denomination_by_hash_from_state (ksh, 3742 &h_denom_pubs[i], 3743 NULL, 3744 NULL); 3745 if (NULL == hd) 3746 return TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN; 3747 3748 GNUNET_assert (NULL != dk); 3749 3750 if (GNUNET_CRYPTO_BSA_CS != 3751 hd->denom_pub.bsign_pub_key->cipher) 3752 return TALER_EC_EXCHANGE_GENERIC_INVALID_DENOMINATION_CIPHER_FOR_OPERATION 3753 ; 3754 3755 if (GNUNET_TIME_absolute_is_future (hd->start_time.abs_time)) 3756 return TALER_EC_EXCHANGE_GENERIC_DENOMINATION_VALIDITY_IN_FUTURE; 3757 3758 if (dk->recoup_possible) 3759 return TALER_EC_EXCHANGE_GENERIC_DENOMINATION_REVOKED; 3760 3761 if (GNUNET_TIME_relative_is_zero (hd->validity_duration)) 3762 return TALER_EC_EXCHANGE_GENERIC_DENOMINATION_EXPIRED; 3763 3764 cdrs[i].h_cs = &hd->h_details.h_cs; 3765 cdrs[i].nonce = &nonces[i]; 3766 } 3767 3768 return TALER_CRYPTO_helper_cs_r_batch_derive (helpers.csdh, 3769 num, 3770 cdrs, 3771 for_melt, 3772 r_pubs); 3773 } 3774 3775 3776 void 3777 TEH_keys_denomination_revoke (const struct TALER_DenominationHashP *h_denom_pub) 3778 { 3779 struct TEH_KeyStateHandle *ksh; 3780 struct HelperDenomination *hd; 3781 3782 ksh = TEH_keys_get_state (); 3783 if (NULL == ksh) 3784 { 3785 GNUNET_break (0); 3786 return; 3787 } 3788 hd = GNUNET_CONTAINER_multihashmap_get (helpers.denom_keys, 3789 &h_denom_pub->hash); 3790 if (NULL == hd) 3791 { 3792 GNUNET_break (0); 3793 return; 3794 } 3795 switch (hd->denom_pub.bsign_pub_key->cipher) 3796 { 3797 case GNUNET_CRYPTO_BSA_INVALID: 3798 break; 3799 case GNUNET_CRYPTO_BSA_RSA: 3800 TALER_CRYPTO_helper_rsa_revoke (helpers.rsadh, 3801 &hd->h_details.h_rsa); 3802 TEH_keys_update_states (); 3803 return; 3804 case GNUNET_CRYPTO_BSA_CS: 3805 TALER_CRYPTO_helper_cs_revoke (helpers.csdh, 3806 &hd->h_details.h_cs); 3807 TEH_keys_update_states (); 3808 return; 3809 } 3810 GNUNET_break (0); 3811 return; 3812 } 3813 3814 3815 enum TALER_ErrorCode 3816 TEH_keys_exchange_sign_ ( 3817 const struct GNUNET_CRYPTO_SignaturePurpose *purpose, 3818 struct TALER_ExchangePublicKeyP *pub, 3819 struct TALER_ExchangeSignatureP *sig) 3820 { 3821 struct TEH_KeyStateHandle *ksh; 3822 3823 ksh = TEH_keys_get_state (); 3824 if (NULL == ksh) 3825 { 3826 /* This *can* happen if the exchange's crypto helper is not running 3827 or had some bad error. */ 3828 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 3829 "Cannot sign request, no valid signing keys available.\n"); 3830 return TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING; 3831 } 3832 return TEH_keys_exchange_sign2_ (ksh, 3833 purpose, 3834 pub, 3835 sig); 3836 } 3837 3838 3839 enum TALER_ErrorCode 3840 TEH_keys_exchange_sign2_ ( 3841 void *cls, 3842 const struct GNUNET_CRYPTO_SignaturePurpose *purpose, 3843 struct TALER_ExchangePublicKeyP *pub, 3844 struct TALER_ExchangeSignatureP *sig) 3845 { 3846 struct TEH_KeyStateHandle *ksh = cls; 3847 enum TALER_ErrorCode ec; 3848 3849 TEH_METRICS_num_signatures[TEH_MT_SIGNATURE_EDDSA]++; 3850 ec = TALER_CRYPTO_helper_esign_sign_ (helpers.esh, 3851 purpose, 3852 pub, 3853 sig); 3854 if (TALER_EC_NONE != ec) 3855 return ec; 3856 { 3857 /* Here we check here that 'pub' is set to an exchange public key that is 3858 actually signed by the master key! Otherwise, we happily continue to 3859 use key material even if the offline signatures have not been made 3860 yet! */ 3861 struct GNUNET_PeerIdentity pid; 3862 struct SigningKey *sk; 3863 3864 pid.public_key = pub->eddsa_pub; 3865 sk = GNUNET_CONTAINER_multipeermap_get (ksh->signkey_map, 3866 &pid); 3867 if (NULL == sk) 3868 { 3869 /* just to be safe, zero out the (valid) signature, as the key 3870 should not or no longer be used */ 3871 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 3872 "Cannot sign, offline key signatures are missing!\n"); 3873 memset (sig, 3874 0, 3875 sizeof (*sig)); 3876 return TALER_EC_EXCHANGE_SIGNKEY_HELPER_OFFLINE_MISSING; 3877 } 3878 } 3879 return ec; 3880 } 3881 3882 3883 void 3884 TEH_keys_exchange_revoke (const struct TALER_ExchangePublicKeyP *exchange_pub) 3885 { 3886 struct TEH_KeyStateHandle *ksh; 3887 3888 ksh = TEH_keys_get_state (); 3889 if (NULL == ksh) 3890 { 3891 GNUNET_break (0); 3892 return; 3893 } 3894 TALER_CRYPTO_helper_esign_revoke (helpers.esh, 3895 exchange_pub); 3896 TEH_keys_update_states (); 3897 } 3898 3899 3900 /** 3901 * Comparator used for a binary search by cherry_pick_date for @a key in the 3902 * `struct KeysResponseData` array. See libc's qsort() and bsearch() functions. 3903 * 3904 * @param key pointer to a `struct GNUNET_TIME_Timestamp` 3905 * @param value pointer to a `struct KeysResponseData` array entry 3906 * @return 0 if time matches, -1 if key is smaller, 1 if key is larger 3907 */ 3908 static int 3909 krd_search_comparator (const void *key, 3910 const void *value) 3911 { 3912 const struct GNUNET_TIME_Timestamp *kd = key; 3913 const struct KeysResponseData *krd = value; 3914 3915 if (GNUNET_TIME_timestamp_cmp (*kd, 3916 >, 3917 krd->cherry_pick_date)) 3918 return -1; 3919 if (GNUNET_TIME_timestamp_cmp (*kd, 3920 <, 3921 krd->cherry_pick_date)) 3922 return 1; 3923 return 0; 3924 } 3925 3926 3927 MHD_RESULT 3928 TEH_keys_get_handler (struct TEH_RequestContext *rc, 3929 const char *const args[]) 3930 { 3931 struct GNUNET_TIME_Timestamp last_issue_date; 3932 const char *etag; 3933 3934 etag = MHD_lookup_connection_value (rc->connection, 3935 MHD_HEADER_KIND, 3936 MHD_HTTP_HEADER_IF_NONE_MATCH); 3937 (void) args; 3938 { 3939 const char *have_cherrypick; 3940 3941 have_cherrypick = MHD_lookup_connection_value (rc->connection, 3942 MHD_GET_ARGUMENT_KIND, 3943 "last_issue_date"); 3944 if (NULL != have_cherrypick) 3945 { 3946 unsigned long long cherrypickn; 3947 3948 if (1 != 3949 sscanf (have_cherrypick, 3950 "%llu", 3951 &cherrypickn)) 3952 { 3953 GNUNET_break_op (0); 3954 return TALER_MHD_reply_with_error (rc->connection, 3955 MHD_HTTP_BAD_REQUEST, 3956 TALER_EC_GENERIC_PARAMETER_MALFORMED, 3957 have_cherrypick); 3958 } 3959 /* The following multiplication may overflow; but this should not really 3960 be a problem, as giving back 'older' data than what the client asks for 3961 (given that the client asks for data in the distant future) is not 3962 problematic */ 3963 last_issue_date = GNUNET_TIME_timestamp_from_s (cherrypickn); 3964 } 3965 else 3966 { 3967 last_issue_date = GNUNET_TIME_UNIT_ZERO_TS; 3968 } 3969 } 3970 3971 { 3972 struct TEH_KeyStateHandle *ksh; 3973 const struct KeysResponseData *krd; 3974 3975 ksh = TEH_keys_get_state (); 3976 if ( (NULL == ksh) || 3977 (0 == ksh->krd_array_length) ) 3978 { 3979 if ( ( (SKR_LIMIT <= skr_size) && 3980 (GNUNET_TIME_relative_cmp ( 3981 GNUNET_TIME_absolute_get_duration (rc->start_time), 3982 >, 3983 GNUNET_TIME_UNIT_SECONDS)) ) || 3984 TEH_suicide) 3985 { 3986 return TALER_MHD_reply_with_error ( 3987 rc->connection, 3988 MHD_HTTP_SERVICE_UNAVAILABLE, 3989 TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING, 3990 TEH_suicide 3991 ? "server terminating" 3992 : "too many connections suspended waiting on /keys"); 3993 } 3994 return suspend_request (rc->connection); 3995 } 3996 krd = bsearch (&last_issue_date, 3997 ksh->krd_array, 3998 ksh->krd_array_length, 3999 sizeof (struct KeysResponseData), 4000 &krd_search_comparator); 4001 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 4002 "Filtering /keys by cherry pick date %s found entry %u/%u\n", 4003 GNUNET_TIME_timestamp2s (last_issue_date), 4004 (unsigned int) (krd - ksh->krd_array), 4005 ksh->krd_array_length); 4006 if ( (NULL == krd) && 4007 (ksh->krd_array_length > 0) ) 4008 { 4009 if (! GNUNET_TIME_absolute_is_zero (last_issue_date.abs_time)) 4010 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 4011 "Client provided invalid cherry picking timestamp %s, returning full response\n", 4012 GNUNET_TIME_timestamp2s (last_issue_date)); 4013 krd = &ksh->krd_array[ksh->krd_array_length - 1]; 4014 } 4015 if (NULL == krd) 4016 { 4017 /* Likely keys not ready *yet*. 4018 Wait until they are. */ 4019 return suspend_request (rc->connection); 4020 } 4021 if ( (NULL != etag) && 4022 (0 == strcmp (etag, 4023 krd->etag)) ) 4024 return TEH_RESPONSE_reply_not_modified (rc->connection, 4025 krd->etag, 4026 &setup_general_response_headers, 4027 ksh); 4028 4029 return MHD_queue_response ( 4030 rc->connection, 4031 MHD_HTTP_OK, 4032 (TALER_MHD_CT_DEFLATE == 4033 TALER_MHD_can_compress (rc->connection, 4034 TALER_MHD_CT_DEFLATE)) 4035 ? krd->response_compressed 4036 : krd->response_uncompressed); 4037 } 4038 } 4039 4040 4041 /** 4042 * Load extension data, like fees, expiration times (!) and age restriction 4043 * flags for the denomination type configured in section @a section_name. 4044 * Before calling this function, the `start` and `validity_duration` times must 4045 * already be initialized in @a meta. 4046 * 4047 * @param section_name section in the configuration to use 4048 * @param[in,out] meta denomination type data to complete 4049 * @return #GNUNET_OK on success 4050 */ 4051 static enum GNUNET_GenericReturnValue 4052 load_extension_data (const char *section_name, 4053 struct TALER_EXCHANGEDB_DenominationKeyMetaData *meta) 4054 { 4055 struct GNUNET_TIME_Relative deposit_duration; 4056 struct GNUNET_TIME_Relative legal_duration; 4057 4058 GNUNET_assert (! GNUNET_TIME_absolute_is_zero (meta->start.abs_time)); /* caller bug */ 4059 if (GNUNET_OK != 4060 GNUNET_CONFIGURATION_get_value_time (TEH_cfg, 4061 section_name, 4062 "DURATION_SPEND", 4063 &deposit_duration)) 4064 { 4065 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 4066 section_name, 4067 "DURATION_SPEND"); 4068 return GNUNET_SYSERR; 4069 } 4070 if (GNUNET_OK != 4071 GNUNET_CONFIGURATION_get_value_time (TEH_cfg, 4072 section_name, 4073 "DURATION_LEGAL", 4074 &legal_duration)) 4075 { 4076 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 4077 section_name, 4078 "DURATION_LEGAL"); 4079 return GNUNET_SYSERR; 4080 } 4081 meta->expire_deposit 4082 = GNUNET_TIME_absolute_to_timestamp ( 4083 GNUNET_TIME_absolute_add (meta->expire_withdraw.abs_time, 4084 deposit_duration)); 4085 meta->expire_legal = GNUNET_TIME_absolute_to_timestamp ( 4086 GNUNET_TIME_absolute_add (meta->expire_deposit.abs_time, 4087 legal_duration)); 4088 if (GNUNET_OK != 4089 TALER_config_get_amount (TEH_cfg, 4090 section_name, 4091 "VALUE", 4092 &meta->value)) 4093 { 4094 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, 4095 "Need amount for option `%s' in section `%s'\n", 4096 "VALUE", 4097 section_name); 4098 return GNUNET_SYSERR; 4099 } 4100 if (0 != strcasecmp (TEH_currency, 4101 meta->value.currency)) 4102 { 4103 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 4104 "Need denomination value in section `%s' to use currency `%s'\n", 4105 section_name, 4106 TEH_currency); 4107 return GNUNET_SYSERR; 4108 } 4109 if (GNUNET_OK != 4110 TALER_config_get_denom_fees (TEH_cfg, 4111 TEH_currency, 4112 section_name, 4113 &meta->fees)) 4114 return GNUNET_SYSERR; 4115 meta->age_mask = load_age_mask (section_name); 4116 return GNUNET_OK; 4117 } 4118 4119 4120 enum GNUNET_GenericReturnValue 4121 TEH_keys_load_fees (struct TEH_KeyStateHandle *ksh, 4122 const struct TALER_DenominationHashP *h_denom_pub, 4123 struct TALER_DenominationPublicKey *denom_pub, 4124 struct TALER_EXCHANGEDB_DenominationKeyMetaData *meta) 4125 { 4126 struct HelperDenomination *hd; 4127 enum GNUNET_GenericReturnValue ok; 4128 4129 hd = GNUNET_CONTAINER_multihashmap_get (helpers.denom_keys, 4130 &h_denom_pub->hash); 4131 if (NULL == hd) 4132 { 4133 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 4134 "Denomination %s not known\n", 4135 GNUNET_h2s (&h_denom_pub->hash)); 4136 return GNUNET_NO; 4137 } 4138 meta->start = hd->start_time; 4139 meta->expire_withdraw = GNUNET_TIME_absolute_to_timestamp ( 4140 GNUNET_TIME_absolute_add (meta->start.abs_time, 4141 hd->validity_duration)); 4142 ok = load_extension_data (hd->section_name, 4143 meta); 4144 if (GNUNET_OK == ok) 4145 { 4146 GNUNET_assert (GNUNET_CRYPTO_BSA_INVALID != 4147 hd->denom_pub.bsign_pub_key->cipher); 4148 TALER_denom_pub_copy (denom_pub, 4149 &hd->denom_pub); 4150 } 4151 else 4152 { 4153 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 4154 "No fees for `%s', voiding key\n", 4155 hd->section_name); 4156 memset (denom_pub, 4157 0, 4158 sizeof (*denom_pub)); 4159 } 4160 return ok; 4161 } 4162 4163 4164 enum GNUNET_GenericReturnValue 4165 TEH_keys_get_timing (const struct TALER_ExchangePublicKeyP *exchange_pub, 4166 struct TALER_EXCHANGEDB_SignkeyMetaData *meta) 4167 { 4168 struct TEH_KeyStateHandle *ksh; 4169 struct HelperSignkey *hsk; 4170 struct GNUNET_PeerIdentity pid; 4171 4172 ksh = TEH_keys_get_state_for_management_only (); 4173 if (NULL == ksh) 4174 { 4175 GNUNET_break (0); 4176 return GNUNET_SYSERR; 4177 } 4178 4179 pid.public_key = exchange_pub->eddsa_pub; 4180 hsk = GNUNET_CONTAINER_multipeermap_get (helpers.esign_keys, 4181 &pid); 4182 if (NULL == hsk) 4183 { 4184 GNUNET_break (0); 4185 return GNUNET_NO; 4186 } 4187 meta->start = hsk->start_time; 4188 4189 meta->expire_sign = GNUNET_TIME_absolute_to_timestamp ( 4190 GNUNET_TIME_absolute_add (meta->start.abs_time, 4191 hsk->validity_duration)); 4192 meta->expire_legal = GNUNET_TIME_absolute_to_timestamp ( 4193 GNUNET_TIME_absolute_add (meta->expire_sign.abs_time, 4194 signkey_legal_duration)); 4195 return GNUNET_OK; 4196 } 4197 4198 4199 /** 4200 * Closure for #add_future_denomkey_cb and #add_future_signkey_cb. 4201 */ 4202 struct FutureBuilderContext 4203 { 4204 /** 4205 * Our key state. 4206 */ 4207 struct TEH_KeyStateHandle *ksh; 4208 4209 /** 4210 * Array of denomination keys. 4211 */ 4212 json_t *denoms; 4213 4214 /** 4215 * Array of signing keys. 4216 */ 4217 json_t *signkeys; 4218 4219 }; 4220 4221 4222 /** 4223 * Function called on all of our current and future denomination keys 4224 * known to the helper process. Filters out those that are current 4225 * and adds the remaining denomination keys (with their configuration 4226 * data) to the JSON array. 4227 * 4228 * @param cls the `struct FutureBuilderContext *` 4229 * @param h_denom_pub hash of the denomination public key 4230 * @param value a `struct HelperDenomination` 4231 * @return #GNUNET_OK (continue to iterate) 4232 */ 4233 static enum GNUNET_GenericReturnValue 4234 add_future_denomkey_cb (void *cls, 4235 const struct GNUNET_HashCode *h_denom_pub, 4236 void *value) 4237 { 4238 struct FutureBuilderContext *fbc = cls; 4239 struct HelperDenomination *hd = value; 4240 struct TEH_DenominationKey *dk; 4241 struct TALER_EXCHANGEDB_DenominationKeyMetaData meta = {0}; 4242 4243 dk = GNUNET_CONTAINER_multihashmap_get (fbc->ksh->denomkey_map, 4244 h_denom_pub); 4245 if (NULL != dk) 4246 return GNUNET_OK; /* skip: this key is already active! */ 4247 if (GNUNET_TIME_relative_is_zero (hd->validity_duration)) 4248 return GNUNET_OK; /* this key already expired! */ 4249 meta.start = hd->start_time; 4250 meta.expire_withdraw = GNUNET_TIME_absolute_to_timestamp ( 4251 GNUNET_TIME_absolute_add (meta.start.abs_time, 4252 hd->validity_duration)); 4253 if (GNUNET_OK != 4254 load_extension_data (hd->section_name, 4255 &meta)) 4256 { 4257 /* Woops, couldn't determine fee structure!? */ 4258 return GNUNET_OK; 4259 } 4260 GNUNET_assert ( 4261 0 == 4262 json_array_append_new ( 4263 fbc->denoms, 4264 GNUNET_JSON_PACK ( 4265 TALER_JSON_pack_amount ("value", 4266 &meta.value), 4267 GNUNET_JSON_pack_timestamp ("stamp_start", 4268 meta.start), 4269 GNUNET_JSON_pack_timestamp ("stamp_expire_withdraw", 4270 meta.expire_withdraw), 4271 GNUNET_JSON_pack_timestamp ("stamp_expire_deposit", 4272 meta.expire_deposit), 4273 GNUNET_JSON_pack_timestamp ("stamp_expire_legal", 4274 meta.expire_legal), 4275 TALER_JSON_pack_denom_pub ("denom_pub", 4276 &hd->denom_pub), 4277 TALER_JSON_PACK_DENOM_FEES ("fee", 4278 &meta.fees), 4279 GNUNET_JSON_pack_data_auto ("denom_secmod_sig", 4280 &hd->sm_sig), 4281 GNUNET_JSON_pack_string ("section_name", 4282 hd->section_name)))); 4283 return GNUNET_OK; 4284 } 4285 4286 4287 /** 4288 * Function called on all of our current and future exchange signing keys 4289 * known to the helper process. Filters out those that are current 4290 * and adds the remaining signing keys (with their configuration 4291 * data) to the JSON array. 4292 * 4293 * @param cls the `struct FutureBuilderContext *` 4294 * @param pid actually the exchange public key (type disguised) 4295 * @param value a `struct HelperDenomination` 4296 * @return #GNUNET_OK (continue to iterate) 4297 */ 4298 static enum GNUNET_GenericReturnValue 4299 add_future_signkey_cb (void *cls, 4300 const struct GNUNET_PeerIdentity *pid, 4301 void *value) 4302 { 4303 struct FutureBuilderContext *fbc = cls; 4304 struct HelperSignkey *hsk = value; 4305 struct SigningKey *sk; 4306 struct GNUNET_TIME_Timestamp stamp_expire; 4307 struct GNUNET_TIME_Timestamp legal_end; 4308 4309 sk = GNUNET_CONTAINER_multipeermap_get (fbc->ksh->signkey_map, 4310 pid); 4311 if (NULL != sk) 4312 return GNUNET_OK; /* skip: this key is already active */ 4313 if (GNUNET_TIME_relative_is_zero (hsk->validity_duration)) 4314 return GNUNET_OK; /* this key already expired! */ 4315 stamp_expire = GNUNET_TIME_absolute_to_timestamp ( 4316 GNUNET_TIME_absolute_add (hsk->start_time.abs_time, 4317 hsk->validity_duration)); 4318 legal_end = GNUNET_TIME_absolute_to_timestamp ( 4319 GNUNET_TIME_absolute_add (stamp_expire.abs_time, 4320 signkey_legal_duration)); 4321 GNUNET_assert (0 == 4322 json_array_append_new ( 4323 fbc->signkeys, 4324 GNUNET_JSON_PACK ( 4325 GNUNET_JSON_pack_data_auto ("key", 4326 &hsk->exchange_pub), 4327 GNUNET_JSON_pack_timestamp ("stamp_start", 4328 hsk->start_time), 4329 GNUNET_JSON_pack_timestamp ("stamp_expire", 4330 stamp_expire), 4331 GNUNET_JSON_pack_timestamp ("stamp_end", 4332 legal_end), 4333 GNUNET_JSON_pack_data_auto ("signkey_secmod_sig", 4334 &hsk->sm_sig)))); 4335 return GNUNET_OK; 4336 } 4337 4338 4339 MHD_RESULT 4340 TEH_keys_management_get_keys_handler (const struct TEH_RequestHandler *rh, 4341 struct MHD_Connection *connection) 4342 { 4343 struct TEH_KeyStateHandle *ksh; 4344 json_t *reply; 4345 4346 (void) rh; 4347 ksh = TEH_keys_get_state_for_management_only (); 4348 if (NULL == ksh) 4349 { 4350 return TALER_MHD_reply_with_error (connection, 4351 MHD_HTTP_SERVICE_UNAVAILABLE, 4352 TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING, 4353 "no key state"); 4354 } 4355 sync_key_helpers (&helpers); 4356 if (NULL == ksh->management_keys_reply) 4357 { 4358 struct FutureBuilderContext fbc = { 4359 .ksh = ksh, 4360 .denoms = json_array (), 4361 .signkeys = json_array () 4362 }; 4363 4364 GNUNET_assert (NULL != fbc.denoms); 4365 GNUNET_assert (NULL != fbc.signkeys); 4366 if ( (GNUNET_is_zero (&denom_rsa_sm_pub)) && 4367 (GNUNET_is_zero (&denom_cs_sm_pub)) ) 4368 { 4369 /* Either IPC failed, or neither helper had any denominations configured. */ 4370 json_decref (fbc.denoms); 4371 json_decref (fbc.signkeys); 4372 return TALER_MHD_reply_with_error (connection, 4373 MHD_HTTP_BAD_GATEWAY, 4374 TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE, 4375 NULL); 4376 } 4377 if (GNUNET_is_zero (&esign_sm_pub)) 4378 { 4379 json_decref (fbc.denoms); 4380 json_decref (fbc.signkeys); 4381 return TALER_MHD_reply_with_error (connection, 4382 MHD_HTTP_BAD_GATEWAY, 4383 TALER_EC_EXCHANGE_SIGNKEY_HELPER_UNAVAILABLE, 4384 NULL); 4385 } 4386 GNUNET_CONTAINER_multihashmap_iterate (helpers.denom_keys, 4387 &add_future_denomkey_cb, 4388 &fbc); 4389 GNUNET_CONTAINER_multipeermap_iterate (helpers.esign_keys, 4390 &add_future_signkey_cb, 4391 &fbc); 4392 reply = GNUNET_JSON_PACK ( 4393 GNUNET_JSON_pack_array_steal ("future_denoms", 4394 fbc.denoms), 4395 GNUNET_JSON_pack_array_steal ("future_signkeys", 4396 fbc.signkeys), 4397 GNUNET_JSON_pack_data_auto ("master_pub", 4398 &TEH_master_public_key), 4399 GNUNET_JSON_pack_data_auto ("denom_secmod_public_key", 4400 &denom_rsa_sm_pub), 4401 GNUNET_JSON_pack_data_auto ("denom_secmod_cs_public_key", 4402 &denom_cs_sm_pub), 4403 GNUNET_JSON_pack_data_auto ("signkey_secmod_public_key", 4404 &esign_sm_pub)); 4405 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 4406 "Returning GET /management/keys response:\n"); 4407 if (NULL == reply) 4408 { 4409 GNUNET_break (0); 4410 return TALER_MHD_reply_with_error (connection, 4411 MHD_HTTP_INTERNAL_SERVER_ERROR, 4412 TALER_EC_GENERIC_JSON_ALLOCATION_FAILURE, 4413 NULL); 4414 } 4415 GNUNET_assert (NULL == ksh->management_keys_reply); 4416 ksh->management_keys_reply = reply; 4417 } 4418 else 4419 { 4420 reply = ksh->management_keys_reply; 4421 } 4422 return TALER_MHD_reply_json (connection, 4423 reply, 4424 MHD_HTTP_OK); 4425 } 4426 4427 4428 /* end of taler-exchange-httpd_keys.c */