donau-httpd_get-keys.c (45802B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2023-2024 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 donau-httpd_get-keys.c 18 * @brief management of our various keys 19 * @author Christian Grothoff 20 * @author Özgür Kesim 21 * @author Pius Loosli 22 * @author Johannes Casaburi 23 */ 24 #include <donau_config.h> 25 #include <taler/taler_json_lib.h> 26 #include <taler/taler_mhd_lib.h> 27 #include "donau_json_lib.h" 28 #include "donau-httpd.h" 29 #include "donau-httpd_get-keys.h" 30 #include "donau-httpd_get-config.h" 31 #include "donaudb_lib.h" 32 #include "donau-database/insert_donation_unit.h" 33 #include "donau-database/insert_signing_key.h" 34 #include "donau-database/iterate_donation_units.h" 35 #include "donau-database/iterate_active_signing_keys.h" 36 #include "donau-database/preflight.h" 37 #include "donau_util.h" 38 39 40 /** 41 * @brief All information about an donau online signing key (which is used to 42 * sign messages from the donau). 43 */ 44 struct SigningKey 45 { 46 47 /** 48 * The donau's (online signing) public key. 49 */ 50 struct DONAU_DonauPublicKeyP donau_pub; 51 52 /** 53 * Meta data about the signing key, such as validity periods. 54 */ 55 struct DONAUDB_SignkeyMetaData meta; 56 57 /** 58 * Did we lose the private keys? // NEEDED? 59 */ 60 bool lost; 61 }; 62 63 64 /** 65 * Snapshot of the (coin and signing) keys (including private keys) of 66 * the exchange. There can be multiple instances of this struct, as it is 67 * reference counted and only destroyed once the last user is done 68 * with it. The current instance is acquired using 69 * #TEH_KS_acquire(). Using this function increases the 70 * reference count. The contents of this structure (except for the 71 * reference counter) should be considered READ-ONLY until it is 72 * ultimately destroyed (as there can be many concurrent users). 73 */ 74 struct DH_KeyStateHandle 75 { 76 77 /** 78 * For which (global) key_generation was this data structure created? 79 * Used to check when we are outdated and need to be re-generated. 80 */ 81 uint64_t key_generation; 82 83 /** 84 * When did we initiate the key reloading? 85 */ 86 struct GNUNET_TIME_Timestamp reload_time; 87 88 /** 89 * When does our online signing key expire and we 90 * thus need to re-generate this response? 91 */ 92 struct GNUNET_TIME_Timestamp signature_expires; 93 94 /** 95 * Response to return if the client supports (deflate) compression. 96 */ 97 struct MHD_Response *response_compressed; 98 99 /** 100 * Response to return if the client does not support compression. 101 */ 102 struct MHD_Response *response_uncompressed; 103 104 /** 105 * ETag for these responses. 106 */ 107 char *etag; 108 109 }; 110 111 112 /** 113 * RSA security module public key, all zero if not known. 114 */ 115 static struct TALER_SecurityModulePublicKeyP donation_unit_rsa_sm_pub; 116 117 /** 118 * CS security module public key, all zero if not known. 119 */ 120 static struct TALER_SecurityModulePublicKeyP donation_unit_cs_sm_pub; 121 122 /** 123 * EdDSA security module public key, all zero if not known. 124 */ 125 static struct TALER_SecurityModulePublicKeyP esign_sm_pub; 126 127 /** 128 * Counter incremented whenever we have a reason to re-build the keys because 129 * something external changed. See #DH_keys_get_state() for uses of this 130 * variable. 131 */ 132 static uint64_t key_generation; 133 134 /** 135 * Handle for the esign/EdDSA helper. 136 */ 137 static struct TALER_CRYPTO_ExchangeSignHelper *esh; 138 139 /** 140 * Handle for the donation_unit/RSA helper. 141 */ 142 static struct TALER_CRYPTO_RsaDenominationHelper *rsadh; 143 144 /** 145 * Handle for the donation_unit/CS helper. 146 */ 147 static struct TALER_CRYPTO_CsDenominationHelper *csdh; 148 149 /** 150 * Map from H(rsa_pub) or H(cs_pub) to `struct DH_DonationUnitKey` entries. 151 */ 152 static struct GNUNET_CONTAINER_MultiHashMap *du_keys; 153 154 /** 155 * Map from `struct TALER_ExchangePublicKey` to `struct SigningKey` 156 * entries. Based on the fact that a `struct GNUNET_PeerIdentity` is also 157 * an EdDSA public key. 158 */ 159 static struct GNUNET_CONTAINER_MultiPeerMap *esign_keys; 160 161 /** 162 * Stores the latest generation of our key state. 163 */ 164 static struct DH_KeyStateHandle *key_state; 165 166 167 /** 168 * Add the headers we want to set for every /keys response. 169 * 170 * @param cls the key state to use 171 * @param[in,out] response the response to modify 172 */ 173 static void 174 setup_general_response_headers (void *cls, 175 struct MHD_Response *response) 176 { 177 struct DH_KeyStateHandle *ksh = cls; 178 char dat[128]; 179 180 TALER_MHD_add_global_headers (response, 181 true); 182 GNUNET_break ( 183 MHD_YES == MHD_add_response_header (response, 184 MHD_HTTP_HEADER_CONTENT_TYPE, 185 "application/json")); 186 TALER_MHD_get_date_string (ksh->reload_time.abs_time, dat); 187 GNUNET_break ( 188 MHD_YES == MHD_add_response_header (response, 189 MHD_HTTP_HEADER_LAST_MODIFIED, 190 dat)); 191 /* Set cache control headers: our response varies depending on these headers */ 192 GNUNET_break ( 193 MHD_YES == MHD_add_response_header (response, 194 MHD_HTTP_HEADER_VARY, 195 MHD_HTTP_HEADER_ACCEPT_ENCODING)); 196 /* Information is always public, revalidate after 1 hour */ 197 GNUNET_break ( 198 MHD_YES == MHD_add_response_header (response, 199 MHD_HTTP_HEADER_CACHE_CONTROL, 200 "public,max-age=3600")); 201 } 202 203 204 /** 205 * Initialize @a ksh using the given values for @a signkeys, 206 * and @a denoms. 207 * 208 * @param[in,out] ksh key state handle we build @a ksh for 209 * @param[in,out] signkeys list of sign keys to return 210 * @param[in,out] donation_units list of grouped denominations to return 211 * @return #GNUNET_OK on success 212 */ 213 static enum GNUNET_GenericReturnValue 214 create_keys_response (struct DH_KeyStateHandle *ksh, 215 json_t *signkeys, 216 json_t *donation_units) 217 { 218 json_t *keys; 219 char *keys_json; 220 void *keys_jsonz; 221 size_t keys_jsonz_size; 222 int comp; 223 char etag[sizeof (struct GNUNET_HashCode) * 2]; 224 225 GNUNET_assert (NULL != signkeys); 226 GNUNET_assert (NULL != donation_units); 227 GNUNET_assert (NULL != DH_currency); 228 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 229 "Creating /keys response\n"); 230 231 keys = GNUNET_JSON_PACK ( 232 GNUNET_JSON_pack_string ("version", 233 DONAU_PROTOCOL_VERSION), 234 GNUNET_JSON_pack_string ("base_url", 235 DH_base_url), 236 GNUNET_JSON_pack_string ("currency", 237 DH_currency), 238 GNUNET_JSON_pack_string ("legal_domain", 239 DH_legal_domain), 240 GNUNET_JSON_pack_array_incref ("signkeys", 241 signkeys), 242 GNUNET_JSON_pack_array_incref ("donation_units", 243 donation_units)); 244 GNUNET_assert (NULL != keys); 245 246 /* Convert /keys response to UTF8-String */ 247 keys_json = json_dumps (keys, 248 JSON_INDENT (2)); 249 json_decref (keys); 250 GNUNET_assert (NULL != keys_json); 251 252 /* Keep copy for later compression... */ 253 keys_jsonz = GNUNET_strdup (keys_json); 254 keys_jsonz_size = strlen (keys_json); 255 256 /* hash to compute etag */ 257 { 258 struct GNUNET_HashCode ehash; 259 char *end; 260 261 GNUNET_CRYPTO_hash (keys_jsonz, 262 keys_jsonz_size, 263 &ehash); 264 end = GNUNET_STRINGS_data_to_string (&ehash, 265 sizeof (ehash), 266 etag, 267 sizeof (etag)); 268 *end = '\0'; 269 } 270 271 /* Create uncompressed response */ 272 ksh->response_uncompressed 273 = MHD_create_response_from_buffer (keys_jsonz_size, 274 keys_json, 275 MHD_RESPMEM_MUST_FREE); 276 GNUNET_assert (NULL != ksh->response_uncompressed); 277 setup_general_response_headers (ksh, 278 ksh->response_uncompressed); 279 GNUNET_break (MHD_YES == 280 MHD_add_response_header (ksh->response_uncompressed, 281 MHD_HTTP_HEADER_ETAG, 282 etag)); 283 /* Also compute compressed version of /keys response */ 284 comp = TALER_MHD_body_compress (&keys_jsonz, 285 &keys_jsonz_size); 286 ksh->response_compressed 287 = MHD_create_response_from_buffer (keys_jsonz_size, 288 keys_jsonz, 289 MHD_RESPMEM_MUST_FREE); 290 GNUNET_assert (NULL != ksh->response_compressed); 291 /* If the response is actually compressed, set the 292 respective header. */ 293 GNUNET_assert ( (MHD_YES != comp) || 294 (MHD_YES == 295 MHD_add_response_header (ksh->response_compressed, 296 MHD_HTTP_HEADER_CONTENT_ENCODING, 297 "deflate")) ); 298 setup_general_response_headers (ksh, 299 ksh->response_compressed); 300 /* Set cache control headers: our response varies depending on these headers */ 301 GNUNET_break (MHD_YES == 302 MHD_add_response_header (ksh->response_compressed, 303 MHD_HTTP_HEADER_VARY, 304 MHD_HTTP_HEADER_ACCEPT_ENCODING)); 305 /* Information is always public, revalidate after 1 day */ 306 GNUNET_break (MHD_YES == 307 MHD_add_response_header (ksh->response_compressed, 308 MHD_HTTP_HEADER_CACHE_CONTROL, 309 "public,max-age=86400")); 310 GNUNET_break (MHD_YES == 311 MHD_add_response_header (ksh->response_compressed, 312 MHD_HTTP_HEADER_ETAG, 313 etag)); 314 ksh->etag = GNUNET_strdup (etag); 315 return GNUNET_OK; 316 } 317 318 319 /** 320 * Closure for #insert_donation_unit_cb and #add_signkey_cb. 321 */ 322 struct KeysBuilderContext 323 { 324 325 /** 326 * Array of donation unit keys. 327 */ 328 json_t *donation_units; 329 330 /** 331 * Array of signing keys. 332 */ 333 json_t *signkeys; 334 335 }; 336 337 /** 338 * Function called for all signing keys, used to build up the 339 * respective JSON response. 340 * 341 * @param cls a `struct KeysBuilderContext *` with the array to append keys to 342 * @param pid the donau public key (in type disguise) 343 * @param value a `struct SigningKey` 344 * @return #GNUNET_OK (continue to iterate) 345 */ 346 static enum GNUNET_GenericReturnValue 347 add_sign_key_cb (void *cls, 348 const struct GNUNET_PeerIdentity *pid, 349 void *value) 350 { 351 struct KeysBuilderContext *ctx = cls; 352 struct SigningKey *sk = value; 353 354 (void) pid; 355 GNUNET_assert ( 356 0 == 357 json_array_append_new ( 358 ctx->signkeys, 359 GNUNET_JSON_PACK ( 360 GNUNET_JSON_pack_timestamp ("stamp_start", 361 sk->meta.valid_from), 362 GNUNET_JSON_pack_timestamp ("stamp_expire", 363 sk->meta.expire_sign), 364 GNUNET_JSON_pack_data_auto ("key", 365 &sk->donau_pub)))); 366 return GNUNET_OK; 367 } 368 369 370 /** 371 * Function called on all of our current and future donation unit keys 372 * known to the helper process. Filters out those that are current 373 * and adds the remaining donation unit keys (with their configuration 374 * data) to the JSON array. 375 * 376 * @param cls the `struct KeysBuilderContext *` 377 * @param h_du_pub hash of the donation unit public key 378 * @param value a `struct DH_DonationUnitKey` 379 * @return #GNUNET_OK (continue to iterate) 380 */ 381 static enum GNUNET_GenericReturnValue 382 insert_donation_unit_cb (void *cls, 383 const struct GNUNET_HashCode *h_du_pub, 384 void *value) 385 { 386 struct KeysBuilderContext *kbc = cls; 387 struct DH_DonationUnitKey *du = value; 388 389 (void) h_du_pub; 390 GNUNET_assert ( 391 0 == json_array_append_new ( 392 kbc->donation_units, 393 GNUNET_JSON_PACK ( 394 DONAU_JSON_pack_donation_unit_pub ("donation_unit_pub", 395 &du->donation_unit_pub), 396 GNUNET_JSON_pack_uint64 ("year", 397 du->validity_year), 398 GNUNET_JSON_pack_bool ("lost", 399 du->lost), 400 TALER_JSON_pack_amount ("value", 401 &du->value) 402 ))); 403 return GNUNET_OK; 404 } 405 406 407 /** 408 * Update the "/keys" responses in @a ksh, computing the detailed replies. 409 * 410 * This function is to recompute all (including cherry-picked) responses we 411 * might want to return, based on the state already in @a ksh. 412 * 413 * @param[in,out] ksh state handle to update 414 * @return #GNUNET_OK on success 415 */ 416 static enum GNUNET_GenericReturnValue 417 finish_keys_response (struct DH_KeyStateHandle *ksh) 418 { 419 enum GNUNET_GenericReturnValue ret = GNUNET_SYSERR; 420 struct KeysBuilderContext kbc; 421 422 kbc.signkeys = json_array (); 423 GNUNET_assert (NULL != kbc.signkeys); 424 kbc.donation_units = json_array (); 425 GNUNET_assert (NULL != kbc.donation_units); 426 GNUNET_CONTAINER_multipeermap_iterate (esign_keys, 427 &add_sign_key_cb, 428 &kbc); 429 430 if (0 == json_array_size (kbc.signkeys)) 431 { 432 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 433 "No online signing keys available. Refusing to generate /keys response.\n"); 434 ret = GNUNET_NO; 435 goto CLEANUP; 436 } 437 GNUNET_CONTAINER_multihashmap_iterate (du_keys, 438 &insert_donation_unit_cb, 439 &kbc); 440 441 if (0 == json_array_size (kbc.donation_units)) 442 { 443 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 444 "No donation units available. Refusing to generate /keys response.\n"); 445 ret = GNUNET_NO; 446 goto CLEANUP; 447 } 448 449 if (GNUNET_OK != 450 create_keys_response (ksh, 451 kbc.signkeys, 452 kbc.donation_units)) 453 { 454 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 455 "Failed to generate key response data\n"); 456 goto CLEANUP; 457 } 458 459 ret = GNUNET_OK; 460 461 CLEANUP: 462 if (NULL != kbc.donation_units) 463 json_decref (kbc.donation_units); 464 if (NULL != kbc.signkeys) 465 json_decref (kbc.signkeys); 466 return ret; 467 } 468 469 470 /** 471 * Free donation unit key data. 472 * 473 * @param cls a `struct DH_KeyStateHandle`, unused 474 * @param h_du_pub hash of the donation unit public key, unused 475 * @param value a `struct DH_DonationUnitKey` to free 476 * @return #GNUNET_OK (continue to iterate) 477 */ 478 static enum GNUNET_GenericReturnValue 479 clear_donation_unit_cb (void *cls, 480 const struct GNUNET_HashCode *h_du_pub, 481 void *value) 482 { 483 struct DH_DonationUnitKey *dk = value; 484 485 (void) cls; 486 (void) h_du_pub; 487 DONAU_donation_unit_pub_free (&dk->donation_unit_pub); 488 GNUNET_free (dk); 489 return GNUNET_OK; 490 } 491 492 493 /** 494 * Free donation unit key data. 495 * 496 * @param cls a `struct DH_KeyStateHandle`, unused 497 * @param pid the online signing key (type-disguised), unused 498 * @param value a `struct SigningKey` to free 499 * @return #GNUNET_OK (continue to iterate) 500 */ 501 static enum GNUNET_GenericReturnValue 502 clear_signkey_cb (void *cls, 503 const struct GNUNET_PeerIdentity *pid, 504 void *value) 505 { 506 struct SigningKey *sk = value; 507 508 (void) cls; 509 (void) pid; 510 GNUNET_free (sk); 511 return GNUNET_OK; 512 } 513 514 515 /** 516 * Synchronize helper state. Polls the key helper for updates. 517 */ 518 static void 519 sync_key_helpers (void) 520 { 521 TALER_CRYPTO_helper_rsa_poll (rsadh); 522 TALER_CRYPTO_helper_cs_poll (csdh); 523 TALER_CRYPTO_helper_esign_poll (esh); 524 } 525 526 527 /** 528 * Check that the given RSA security module's public key is the one 529 * we have pinned. If it does not match, we die hard. 530 * 531 * @param sm_pub RSA security module public key to check 532 */ 533 static void 534 check_donation_unit_rsa_sm_pub (const struct 535 TALER_SecurityModulePublicKeyP *sm_pub) 536 { 537 if (0 != 538 GNUNET_memcmp (sm_pub, 539 &donation_unit_rsa_sm_pub)) 540 { 541 if (! GNUNET_is_zero (&donation_unit_rsa_sm_pub)) 542 { 543 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 544 "Our RSA security module changed its key. This must not happen.\n") 545 ; 546 GNUNET_assert (0); 547 } 548 donation_unit_rsa_sm_pub = *sm_pub; /* TOFU ;-) */ 549 } 550 } 551 552 553 /** 554 * Check that the given CS security module's public key is the one 555 * we have pinned. If it does not match, we die hard. 556 * 557 * @param sm_pub RSA security module public key to check 558 */ 559 static void 560 check_donation_unit_cs_sm_pub (const struct 561 TALER_SecurityModulePublicKeyP *sm_pub) 562 { 563 if (0 != 564 GNUNET_memcmp (sm_pub, 565 &donation_unit_cs_sm_pub)) 566 { 567 if (! GNUNET_is_zero (&donation_unit_cs_sm_pub)) 568 { 569 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 570 "Our CS security module changed its key. This must not happen.\n") 571 ; 572 GNUNET_assert (0); 573 } 574 donation_unit_cs_sm_pub = *sm_pub; /* TOFU ;-) */ 575 } 576 } 577 578 579 /** 580 * Check that the given EdDSA security module's public key is the one 581 * we have pinned. If it does not match, we die hard. 582 * 583 * @param sm_pub EdDSA security module public key to check 584 */ 585 static void 586 check_esign_sm_pub (const struct TALER_SecurityModulePublicKeyP *sm_pub) 587 { 588 if (0 != 589 GNUNET_memcmp (sm_pub, 590 &esign_sm_pub)) 591 { 592 if (! GNUNET_is_zero (&esign_sm_pub)) 593 { 594 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 595 "Our EdDSA security module changed its key. This must not happen.\n") 596 ; 597 GNUNET_assert (0); 598 } 599 esign_sm_pub = *sm_pub; /* TOFU ;-) */ 600 } 601 } 602 603 604 void 605 DH_keys_finished () 606 { 607 if (NULL != rsadh) 608 { 609 TALER_CRYPTO_helper_rsa_disconnect (rsadh); 610 rsadh = NULL; 611 } 612 if (NULL != csdh) 613 { 614 TALER_CRYPTO_helper_cs_disconnect (csdh); 615 csdh = NULL; 616 } 617 if (NULL != esh) 618 { 619 TALER_CRYPTO_helper_esign_disconnect (esh); 620 esh = NULL; 621 } 622 if (NULL != du_keys) 623 { 624 GNUNET_CONTAINER_multihashmap_iterate (du_keys, 625 &clear_donation_unit_cb, 626 NULL); 627 GNUNET_CONTAINER_multihashmap_destroy (du_keys); 628 du_keys = NULL; 629 } 630 if (NULL != esign_keys) 631 { 632 GNUNET_CONTAINER_multipeermap_iterate (esign_keys, 633 &clear_signkey_cb, 634 NULL); 635 GNUNET_CONTAINER_multipeermap_destroy (esign_keys); 636 esign_keys = NULL; 637 } 638 } 639 640 641 static void 642 destroy_key_state (struct DH_KeyStateHandle *ksh) 643 { 644 if (NULL != ksh->response_compressed) 645 MHD_destroy_response (ksh->response_compressed); 646 if (NULL != ksh->response_uncompressed) 647 MHD_destroy_response (ksh->response_uncompressed); 648 GNUNET_free (ksh->etag); 649 GNUNET_free (ksh); 650 } 651 652 653 /** 654 * Function called with information about available keys for signing. Usually 655 * only called once per key upon connect. Also called again in case a key is 656 * being revoked, in that case with an @a end_time of zero. 657 * 658 * @param cls NULL 659 * @param section_name name of the donation_unit type in the configuration; 660 * NULL if the key has been revoked or purged 661 * @param start_time when does the key become available for signing; 662 * zero if the key has been revoked or purged 663 * @param validity_duration how long does the key remain available for signing; 664 * zero if the key has been revoked or purged 665 * @param h_rsa hash of the @a donation_unit_pub that is available (or was purged) 666 * @param bs_pub the public key itself, NULL if the key was revoked or purged 667 * @param sm_pub public key of the security module, NULL if the key was revoked or purged 668 * @param sm_sig signature from the security module 669 */ 670 static void 671 helper_rsa_cb ( 672 void *cls, 673 const char *section_name, 674 struct GNUNET_TIME_Timestamp start_time, 675 struct GNUNET_TIME_Relative validity_duration, 676 const struct TALER_RsaPubHashP *h_rsa, 677 struct GNUNET_CRYPTO_BlindSignPublicKey *bs_pub, 678 const struct TALER_SecurityModulePublicKeyP *sm_pub, 679 const struct TALER_SecurityModuleSignatureP *sm_sig) 680 { 681 struct DH_DonationUnitKey *du; 682 struct TALER_Amount value; 683 enum GNUNET_DB_QueryStatus qs; 684 685 (void) cls; 686 (void) sm_sig; /* not using offline signatures */ 687 GNUNET_assert (GNUNET_CRYPTO_BSA_RSA == bs_pub->cipher); 688 if (GNUNET_OK != 689 TALER_config_get_amount (DH_cfg, 690 section_name, 691 "value", 692 &value)) 693 { 694 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 695 "RSA helper provided key for configuration section `%s' that has no `value' option set\n", 696 section_name); 697 return; 698 } 699 /* FIXME: could additionally sanity-check that this 700 section actually has CIPHER = RSA, etc. */ 701 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 702 "RSA helper announces key %s for donation_unit type %s with validity %s\n", 703 GNUNET_h2s (&h_rsa->hash), 704 section_name, 705 GNUNET_STRINGS_relative_time_to_string (validity_duration, 706 false)); 707 du = GNUNET_CONTAINER_multihashmap_get (du_keys, 708 &h_rsa->hash); 709 if (NULL != du) 710 { 711 /* only update 'lost' status */ 712 du->lost = GNUNET_TIME_relative_is_zero (validity_duration); 713 return; 714 } 715 GNUNET_assert (NULL != sm_pub); 716 check_donation_unit_rsa_sm_pub (sm_pub); 717 718 du = GNUNET_new (struct DH_DonationUnitKey); 719 du->h_donation_unit_pub.hash = h_rsa->hash; 720 du->donation_unit_pub.bsign_pub_key 721 = GNUNET_CRYPTO_bsign_pub_incref (bs_pub); 722 du->validity_year = GNUNET_TIME_time_to_year (start_time.abs_time); 723 du->value = value; 724 du->lost = GNUNET_TIME_relative_is_zero (validity_duration); 725 726 GNUNET_assert ( 727 GNUNET_OK == 728 GNUNET_CONTAINER_multihashmap_put ( 729 du_keys, 730 &du->h_donation_unit_pub.hash, 731 du, 732 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); 733 734 qs = DONAUDB_insert_donation_unit (DH_context, 735 &du->h_donation_unit_pub, 736 &du->donation_unit_pub, 737 du->validity_year, 738 &du->value); 739 if (qs < 0) 740 { 741 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 742 "Failed to insert donation units\n"); 743 GNUNET_SCHEDULER_shutdown (); 744 DH_global_ret = EXIT_FAILURE; 745 return; 746 } 747 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 748 "Inserted RSA donation unit of %s\n", 749 TALER_amount2s (&value)); 750 key_generation++; 751 } 752 753 754 /** 755 * Function called with information about available CS keys for signing. Usually 756 * only called once per key upon connect. Also called again in case a key is 757 * being revoked, in that case with an @a end_time of zero. 758 * 759 * @param cls NULL 760 * @param section_name name of the donation unit type in the configuration; 761 * NULL if the key has been revoked or purged 762 * @param start_time when does the key become available for signing; 763 * zero if the key has been revoked or purged 764 * @param validity_duration how long does the key remain available for signing; 765 * zero if the key has been revoked or purged 766 * @param h_cs hash of the @a donation_unit_pub that is available (or was purged) 767 * @param bs_pub the public key itself, NULL if the key was revoked or purged 768 * @param sm_pub the public key of the security module 769 * @param sm_sig signature by the security module 770 */ 771 static void 772 helper_cs_cb ( 773 void *cls, 774 const char *section_name, 775 struct GNUNET_TIME_Timestamp start_time, 776 struct GNUNET_TIME_Relative validity_duration, 777 const struct TALER_CsPubHashP *h_cs, 778 struct GNUNET_CRYPTO_BlindSignPublicKey *bs_pub, 779 const struct TALER_SecurityModulePublicKeyP *sm_pub, 780 const struct TALER_SecurityModuleSignatureP *sm_sig) 781 { 782 struct DH_DonationUnitKey *du; 783 struct TALER_Amount value; 784 enum GNUNET_DB_QueryStatus qs; 785 786 (void) cls; 787 (void) sm_sig; /* we are not using offline signatures */ 788 GNUNET_assert (GNUNET_CRYPTO_BSA_CS == bs_pub->cipher); 789 if (GNUNET_OK != 790 TALER_config_get_amount (DH_cfg, 791 section_name, 792 "value", 793 &value)) 794 { 795 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 796 "CS helper provided key for configuration section `%s' that has no `value' option set\n", 797 section_name); 798 return; 799 } 800 /* FIXME: could additionally sanity-check that this 801 section actually has CIPHER = CS, etc. */ 802 803 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 804 "CS helper announces key %s for donation unit type %s with validity %s\n", 805 GNUNET_h2s (&h_cs->hash), 806 section_name, 807 GNUNET_STRINGS_relative_time_to_string (validity_duration, 808 false)); 809 du = GNUNET_CONTAINER_multihashmap_get (du_keys, 810 &h_cs->hash); 811 if (NULL != du) 812 { 813 /* should be just an update (revocation!), so update existing entry */ 814 du->lost = GNUNET_TIME_relative_is_zero (validity_duration); 815 return; 816 } 817 GNUNET_assert (NULL != sm_pub); 818 check_donation_unit_cs_sm_pub (sm_pub); 819 820 du = GNUNET_new (struct DH_DonationUnitKey); 821 du->h_donation_unit_pub.hash = h_cs->hash; 822 du->donation_unit_pub.bsign_pub_key 823 = GNUNET_CRYPTO_bsign_pub_incref (bs_pub); 824 du->validity_year = GNUNET_TIME_time_to_year (start_time.abs_time); 825 du->value = value; 826 du->lost = GNUNET_TIME_relative_is_zero (validity_duration); 827 GNUNET_assert ( 828 GNUNET_OK == 829 GNUNET_CONTAINER_multihashmap_put ( 830 du_keys, 831 &du->h_donation_unit_pub.hash, 832 du, 833 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); 834 835 qs = DONAUDB_insert_donation_unit (DH_context, 836 &du->h_donation_unit_pub, 837 &du->donation_unit_pub, 838 du->validity_year, 839 &du->value); 840 if (qs < 0) 841 { 842 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 843 "Failed to insert donation units\n"); 844 GNUNET_SCHEDULER_shutdown (); 845 DH_global_ret = EXIT_FAILURE; 846 return; 847 } 848 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 849 "Inserted CS donation unit of %s\n", 850 TALER_amount2s (&value)); 851 852 key_generation++; 853 } 854 855 856 /** 857 * Function called with information about available keys for signing. Usually 858 * only called once per key upon connect. Also called again in case a key is 859 * being revoked, in that case with an @a end_time of zero. 860 * 861 * @param cls NULL 862 * @param start_time when does the key become available for signing; 863 * zero if the key has been revoked or purged 864 * @param validity_duration how long does the key remain available for signing; 865 * zero if the key has been revoked or purged 866 * @param donau_pub the public key itself, NULL if the key was revoked or purged 867 * @param sm_pub public key of the security module, NULL if the key was revoked or purged 868 * @param sm_sig signature from the security module 869 */ 870 static void 871 helper_esign_cb ( 872 void *cls, 873 struct GNUNET_TIME_Timestamp start_time, 874 struct GNUNET_TIME_Relative validity_duration, 875 const struct TALER_ExchangePublicKeyP *donau_pub, 876 const struct TALER_SecurityModulePublicKeyP *sm_pub, 877 const struct TALER_SecurityModuleSignatureP *sm_sig) 878 { 879 struct SigningKey *sk; 880 struct GNUNET_PeerIdentity pid; 881 unsigned long long expire_legal; 882 /* need to "cast" because secmod works with TALER_ExchangePublicKeyP */ 883 struct DONAU_DonauPublicKeyP donau_pubkey = { 884 .eddsa_pub = donau_pub->eddsa_pub 885 }; 886 enum GNUNET_DB_QueryStatus qs; 887 888 (void) cls; 889 (void) sm_sig; /* not using offline signing */ 890 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 891 "EdDSA helper announces signing key %s with validity %s\n", 892 TALER_B2S (donau_pub), 893 GNUNET_STRINGS_relative_time_to_string (validity_duration, 894 false)); 895 896 pid.public_key = donau_pub->eddsa_pub; 897 sk = GNUNET_CONTAINER_multipeermap_get (esign_keys, 898 &pid); 899 if (NULL != sk) 900 { 901 /* should be just an update (revocation!), so update existing entry */ 902 sk->lost = GNUNET_TIME_relative_is_zero (validity_duration); 903 return; 904 } 905 GNUNET_assert (NULL != sm_pub); 906 check_esign_sm_pub (sm_pub); 907 908 sk = GNUNET_new (struct SigningKey); 909 sk->donau_pub = donau_pubkey; 910 sk->meta.valid_from = start_time; 911 sk->meta.expire_sign 912 = GNUNET_TIME_absolute_to_timestamp ( 913 GNUNET_TIME_absolute_add (start_time.abs_time, 914 validity_duration)); 915 916 if (GNUNET_OK != 917 GNUNET_CONFIGURATION_get_value_number (DH_cfg, 918 "donau", 919 "EXPIRE_LEGAL_YEARS", 920 &expire_legal)) 921 { 922 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 923 "Need EXPIRE_LEGAL_YEARS in section `donau'\n"); 924 GNUNET_SCHEDULER_shutdown (); 925 DH_global_ret = EXIT_FAILURE; 926 return; 927 } 928 sk->meta.expire_legal 929 = GNUNET_TIME_absolute_to_timestamp ( 930 GNUNET_TIME_absolute_add (start_time.abs_time, 931 GNUNET_TIME_relative_multiply ( 932 GNUNET_TIME_UNIT_YEARS, 933 expire_legal))); 934 935 GNUNET_assert ( 936 GNUNET_OK == 937 GNUNET_CONTAINER_multipeermap_put ( 938 esign_keys, 939 &pid, 940 sk, 941 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); 942 943 qs = DONAUDB_insert_signing_key (DH_context, 944 &donau_pubkey, 945 &sk->meta); 946 if (qs < 0) 947 { 948 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 949 "Failed to insert donation units\n"); 950 GNUNET_SCHEDULER_shutdown (); 951 DH_global_ret = EXIT_FAILURE; 952 return; 953 } 954 955 key_generation++; 956 } 957 958 959 enum GNUNET_GenericReturnValue 960 DH_keys_init () 961 { 962 du_keys 963 = GNUNET_CONTAINER_multihashmap_create (1024, 964 GNUNET_YES); 965 esign_keys 966 = GNUNET_CONTAINER_multipeermap_create (32, 967 GNUNET_NO /* MUST BE NO! */); 968 rsadh = TALER_CRYPTO_helper_rsa_connect (DH_cfg, 969 "donau", 970 &helper_rsa_cb, 971 NULL); 972 if (NULL == rsadh) 973 { 974 GNUNET_break (0); 975 DH_keys_finished (); 976 return GNUNET_SYSERR; 977 } 978 csdh = TALER_CRYPTO_helper_cs_connect (DH_cfg, 979 "donau", 980 &helper_cs_cb, 981 NULL); 982 if (NULL == csdh) 983 { 984 GNUNET_break (0); 985 DH_keys_finished (); 986 return GNUNET_SYSERR; 987 } 988 esh = TALER_CRYPTO_helper_esign_connect (DH_cfg, 989 "donau", 990 &helper_esign_cb, 991 NULL); 992 if (NULL == esh) 993 { 994 GNUNET_break (0); 995 DH_keys_finished (); 996 return GNUNET_SYSERR; 997 } 998 return GNUNET_OK; 999 } 1000 1001 1002 /** 1003 * Function called with information about the donau's donation_unit keys. 1004 * 1005 * @param cls NULL 1006 * @param donation_unit_pub public key of the donation_unit 1007 * @param h_donation_unit_pub hash of @a donation_unit_pub 1008 * @param validity_year of the donation unit 1009 * @param value of the donation unit 1010 */ 1011 static enum GNUNET_GenericReturnValue 1012 donation_unit_info_cb ( 1013 void *cls, 1014 const struct DONAU_DonationUnitHashP *h_donation_unit_pub, 1015 const struct DONAU_DonationUnitPublicKey *donation_unit_pub, 1016 uint64_t validity_year, 1017 struct TALER_Amount *value) 1018 { 1019 struct DH_DonationUnitKey *du; 1020 1021 (void) cls; 1022 GNUNET_assert (GNUNET_CRYPTO_BSA_INVALID != 1023 donation_unit_pub->bsign_pub_key->cipher); 1024 du = GNUNET_CONTAINER_multihashmap_get (du_keys, 1025 &h_donation_unit_pub->hash); 1026 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1027 "Got %s key from database\n", 1028 NULL == du ? "unknown" : "known"); 1029 if (NULL != du) 1030 { 1031 /* we already know this, nothing to do */ 1032 return GNUNET_OK; 1033 } 1034 1035 du = GNUNET_new (struct DH_DonationUnitKey); 1036 du->h_donation_unit_pub = *h_donation_unit_pub; 1037 DONAU_donation_unit_pub_deep_copy (&du->donation_unit_pub, 1038 donation_unit_pub); 1039 du->validity_year = validity_year; 1040 du->value = *value; 1041 du->lost = true; /* no private key known, that can only come from the helper! */ 1042 GNUNET_assert ( 1043 GNUNET_OK == 1044 GNUNET_CONTAINER_multihashmap_put (du_keys, 1045 &du->h_donation_unit_pub.hash, 1046 du, 1047 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY) 1048 ); 1049 return GNUNET_OK; 1050 } 1051 1052 1053 /** 1054 * Function called with information about the donau's online signing keys. 1055 * 1056 * @param cls NULL 1057 * @param donau_pub the public key 1058 * @param meta meta data information about the denomination type (expirations) 1059 */ 1060 static void 1061 iterate_active_signing_keys_cb ( 1062 void *cls, 1063 const struct DONAU_DonauPublicKeyP *donau_pub, 1064 struct DONAUDB_SignkeyMetaData *meta) 1065 { 1066 /* The 'pid' is used as the key in the "peer" map... */ 1067 struct GNUNET_PeerIdentity pid = { 1068 .public_key = donau_pub->eddsa_pub 1069 }; 1070 struct SigningKey *sk; 1071 1072 (void) cls; 1073 sk = GNUNET_CONTAINER_multipeermap_get (esign_keys, 1074 &pid); 1075 if (NULL != sk) 1076 { 1077 /* should be just an update (revocation!), so update existing entry */ 1078 return; 1079 } 1080 sk = GNUNET_new (struct SigningKey); 1081 sk->donau_pub = *donau_pub; 1082 sk->meta = *meta; 1083 sk->lost = true; /* no private key known, that can only come from the helper! */ 1084 GNUNET_assert ( 1085 GNUNET_OK == 1086 GNUNET_CONTAINER_multipeermap_put (esign_keys, 1087 &pid, 1088 sk, 1089 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY) 1090 ); 1091 } 1092 1093 1094 /** 1095 * Create a key state. 1096 * 1097 * @return NULL on error (i.e. failed to access database) 1098 */ 1099 static struct DH_KeyStateHandle * 1100 build_key_state () 1101 { 1102 struct DH_KeyStateHandle *ksh; 1103 enum GNUNET_DB_QueryStatus qs; 1104 1105 ksh = GNUNET_new (struct DH_KeyStateHandle); 1106 ksh->signature_expires = GNUNET_TIME_UNIT_FOREVER_TS; 1107 ksh->reload_time = GNUNET_TIME_timestamp_get (); 1108 /* We must use the key_generation from when we STARTED the process! */ 1109 ksh->key_generation = key_generation; 1110 1111 /* NOTE: fetches master-signed signkeys, but ALSO those that were revoked! */ 1112 GNUNET_break (GNUNET_OK == 1113 DONAUDB_preflight (DH_context)); 1114 qs = DONAUDB_iterate_donation_units (DH_context, 1115 &donation_unit_info_cb, 1116 NULL); 1117 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1118 "Fetched %d donation unit keys from DB\n", 1119 (int) qs); 1120 if (qs < 0) 1121 { 1122 GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs); 1123 GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR != qs); 1124 destroy_key_state (ksh); 1125 return NULL; 1126 } 1127 1128 /* NOTE: ONLY fetches active signkeys! */ 1129 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1130 "Fetching active signing keys from DB\n"); 1131 qs = DONAUDB_iterate_active_signing_keys (DH_context, 1132 &iterate_active_signing_keys_cb, 1133 NULL); 1134 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1135 "Fetched %d active signing keys from DB\n", 1136 (int) qs); 1137 if (qs < 0) 1138 { 1139 GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs); 1140 GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR != qs); 1141 destroy_key_state (ksh); 1142 return NULL; 1143 } 1144 1145 if (GNUNET_OK != 1146 finish_keys_response (ksh)) 1147 { 1148 GNUNET_log ( 1149 GNUNET_ERROR_TYPE_WARNING, 1150 "Could not finish /keys response (likely no signing keys available yet)\n"); 1151 destroy_key_state (ksh); 1152 return NULL; 1153 } 1154 1155 return ksh; 1156 } 1157 1158 1159 static struct DH_KeyStateHandle* 1160 DH_keys_get_state () 1161 { 1162 struct DH_KeyStateHandle *old_ksh; 1163 struct DH_KeyStateHandle *ksh; 1164 1165 old_ksh = key_state; 1166 if (NULL == old_ksh) 1167 { 1168 ksh = build_key_state (); 1169 if (NULL == ksh) 1170 return NULL; 1171 key_state = ksh; 1172 return ksh; 1173 } 1174 if ( (old_ksh->key_generation < key_generation) || 1175 (GNUNET_TIME_absolute_is_past (old_ksh->signature_expires.abs_time)) ) 1176 { 1177 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1178 "Rebuilding /keys, generation upgrade from %llu to %llu\n", 1179 (unsigned long long ) old_ksh->key_generation, 1180 (unsigned long long ) key_generation); 1181 ksh = build_key_state (); 1182 key_state = ksh; 1183 destroy_key_state (old_ksh); 1184 return ksh; 1185 } 1186 return old_ksh; 1187 } 1188 1189 1190 enum MHD_Result 1191 DH_handler_get_keys (struct DH_RequestContext *rc, 1192 const char *const args[]) 1193 { 1194 struct MHD_Connection *connection = rc->connection; 1195 struct DH_KeyStateHandle *ksh; 1196 struct MHD_Response *resp; 1197 1198 (void) args; 1199 sync_key_helpers (); 1200 ksh = DH_keys_get_state (); 1201 if (NULL == ksh) 1202 { 1203 if ( (GNUNET_is_zero (&donation_unit_rsa_sm_pub)) && 1204 (GNUNET_is_zero (&donation_unit_cs_sm_pub)) ) 1205 { 1206 /* Either IPC failed, or neither helper had any donation_unit configured. */ 1207 return TALER_MHD_reply_with_error (connection, 1208 MHD_HTTP_BAD_GATEWAY, 1209 TALER_EC_DONAU_DONATION_UNIT_HELPER_UNAVAILABLE, 1210 NULL); 1211 } 1212 if (GNUNET_is_zero (&esign_sm_pub)) 1213 { 1214 return TALER_MHD_reply_with_error (connection, 1215 MHD_HTTP_BAD_GATEWAY, 1216 TALER_EC_DONAU_SIGNKEY_HELPER_UNAVAILABLE, 1217 NULL); 1218 } 1219 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1220 "Failed to build /keys response?\n"); 1221 return TALER_MHD_reply_with_error (connection, 1222 MHD_HTTP_SERVICE_UNAVAILABLE, 1223 TALER_EC_DONAU_GENERIC_KEYS_MISSING, 1224 "failed to create keys response"); 1225 } 1226 resp = (TALER_MHD_CT_DEFLATE == 1227 TALER_MHD_can_compress (connection, 1228 TALER_MHD_CT_DEFLATE)) 1229 ? ksh->response_compressed 1230 : ksh->response_uncompressed; 1231 GNUNET_assert (NULL != resp); 1232 return MHD_queue_response (connection, 1233 MHD_HTTP_OK, 1234 resp); 1235 1236 } 1237 1238 1239 enum TALER_ErrorCode 1240 DH_keys_donau_sign_ ( 1241 const struct GNUNET_CRYPTO_SignaturePurpose *purpose, 1242 struct DONAU_DonauPublicKeyP *pub, 1243 struct DONAU_DonauSignatureP *sig) 1244 { 1245 struct DH_KeyStateHandle *ksh; 1246 enum TALER_ErrorCode ec; 1247 1248 ksh = DH_keys_get_state (); 1249 if (NULL == ksh) 1250 { 1251 /* This *can* happen if the Donau's crypto helper is not running 1252 or had some bad error. */ 1253 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1254 "Cannot sign request, no valid signing keys available.\n"); 1255 return TALER_EC_DONAU_GENERIC_KEYS_MISSING; 1256 } 1257 1258 { 1259 /* need to "cast" because TALER_CRYPTO works with TALER_Exchange.. */ 1260 struct TALER_ExchangePublicKeyP donau_pub; 1261 struct TALER_ExchangeSignatureP donau_sig; 1262 1263 ec = TALER_CRYPTO_helper_esign_sign_ (esh, 1264 purpose, 1265 &donau_pub, 1266 &donau_sig); 1267 if (TALER_EC_NONE != ec) 1268 return ec; 1269 pub->eddsa_pub = donau_pub.eddsa_pub; 1270 sig->eddsa_sig = donau_sig.eddsa_signature; 1271 } 1272 return ec; 1273 } 1274 1275 1276 enum TALER_ErrorCode 1277 DH_keys_donation_unit_batch_sign ( 1278 unsigned int num_bkps, 1279 const struct DONAU_BkpSignData bkps[num_bkps], 1280 struct DONAU_BlindedDonationUnitSignature du_sigs[num_bkps]) 1281 { 1282 struct DH_KeyStateHandle *ksh; 1283 struct DH_DonationUnitKey *du; 1284 struct TALER_CRYPTO_RsaSignRequest rsrs[num_bkps]; 1285 struct TALER_CRYPTO_CsSignRequest csrs[num_bkps]; 1286 struct TALER_BlindedDenominationSignature rs[num_bkps]; 1287 struct TALER_BlindedDenominationSignature cs[num_bkps]; 1288 unsigned int rsrs_pos = 0; 1289 unsigned int csrs_pos = 0; 1290 enum TALER_ErrorCode ec; 1291 1292 ksh = DH_keys_get_state (); 1293 if (NULL == ksh) 1294 return TALER_EC_DONAU_GENERIC_KEYS_MISSING; 1295 for (unsigned int i = 0; i<num_bkps; i++) 1296 { 1297 const struct DONAU_DonationUnitHashP *h_du_pub = 1298 bkps[i].h_donation_unit_pub; 1299 const struct DONAU_BlindedUniqueDonorIdentifier *budi = bkps[i].budi; 1300 1301 du = GNUNET_CONTAINER_multihashmap_get (du_keys, 1302 &h_du_pub->hash); 1303 if (NULL == du) 1304 return TALER_EC_DONAU_GENERIC_DONATION_UNIT_UNKNOWN; 1305 if (budi->blinded_message->cipher != 1306 du->donation_unit_pub.bsign_pub_key->cipher) 1307 return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; 1308 switch (du->donation_unit_pub.bsign_pub_key->cipher) 1309 { 1310 case GNUNET_CRYPTO_BSA_RSA: 1311 /* See DONAU_donation_unit_pub_hash: we guarantee that these 1312 hashes are equivalent! */ 1313 rsrs[rsrs_pos].h_rsa 1314 = (const struct TALER_RsaPubHashP *) &du->h_donation_unit_pub; 1315 rsrs[rsrs_pos].msg 1316 = budi->blinded_message->details.rsa_blinded_message.blinded_msg; 1317 rsrs[rsrs_pos].msg_size 1318 = budi->blinded_message->details.rsa_blinded_message.blinded_msg_size; 1319 rsrs_pos++; 1320 break; 1321 case GNUNET_CRYPTO_BSA_CS: 1322 /* See DONAU_donation_unit_pub_hash: we guarantee that these 1323 hashes are equivalent! */ 1324 csrs[csrs_pos].h_cs 1325 = (const struct TALER_CsPubHashP *) &du->h_donation_unit_pub; 1326 csrs[csrs_pos].blinded_planchet 1327 = &budi->blinded_message->details.cs_blinded_message; 1328 csrs_pos++; 1329 break; 1330 default: 1331 return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; 1332 } 1333 } 1334 1335 if ( (0 != csrs_pos) && 1336 (0 != rsrs_pos) ) 1337 { 1338 memset (rs, 1339 0, 1340 sizeof (rs)); 1341 memset (cs, 1342 0, 1343 sizeof (cs)); 1344 } 1345 ec = TALER_EC_NONE; 1346 if (0 != csrs_pos) 1347 { 1348 ec = TALER_CRYPTO_helper_cs_batch_sign ( 1349 csdh, 1350 csrs_pos, 1351 csrs, 1352 false, // for_melt 1353 cs); 1354 if (TALER_EC_NONE != ec) 1355 { 1356 for (unsigned int i = 0; i<csrs_pos; i++) 1357 { 1358 if (NULL != cs[i].blinded_sig) 1359 { 1360 GNUNET_CRYPTO_blinded_sig_decref (cs[i].blinded_sig); 1361 cs[i].blinded_sig = NULL; 1362 } 1363 } 1364 return ec; 1365 } 1366 } 1367 if (0 != rsrs_pos) 1368 { 1369 ec = TALER_CRYPTO_helper_rsa_batch_sign ( 1370 rsadh, 1371 rsrs_pos, 1372 rsrs, 1373 rs); 1374 if (TALER_EC_NONE != ec) 1375 { 1376 for (unsigned int i = 0; i<csrs_pos; i++) 1377 { 1378 if (NULL != cs[i].blinded_sig) 1379 { 1380 GNUNET_CRYPTO_blinded_sig_decref (cs[i].blinded_sig); 1381 cs[i].blinded_sig = NULL; 1382 } 1383 } 1384 for (unsigned int i = 0; i<rsrs_pos; i++) 1385 { 1386 if (NULL != rs[i].blinded_sig) 1387 { 1388 GNUNET_CRYPTO_blinded_sig_decref (rs[i].blinded_sig); 1389 rs[i].blinded_sig = NULL; 1390 } 1391 } 1392 return ec; 1393 } 1394 } 1395 1396 rsrs_pos = 0; 1397 csrs_pos = 0; 1398 for (unsigned int i = 0; i<num_bkps; i++) 1399 { 1400 const struct DONAU_BlindedUniqueDonorIdentifier *budi = bkps[i].budi; 1401 1402 switch (budi->blinded_message->cipher) 1403 { 1404 case GNUNET_CRYPTO_BSA_RSA: 1405 du_sigs[i].blinded_sig = rs[rsrs_pos++].blinded_sig; 1406 break; 1407 case GNUNET_CRYPTO_BSA_CS: 1408 du_sigs[i].blinded_sig = cs[csrs_pos++].blinded_sig; 1409 break; 1410 default: 1411 GNUNET_assert (0); 1412 } 1413 } 1414 return TALER_EC_NONE; 1415 } 1416 1417 1418 struct DH_DonationUnitKey * 1419 DH_keys_donation_unit_by_hash ( 1420 const struct DONAU_DonationUnitHashP *h_du_pub) 1421 { 1422 return GNUNET_CONTAINER_multihashmap_get (du_keys, 1423 &h_du_pub->hash); 1424 } 1425 1426 1427 enum TALER_ErrorCode 1428 DH_keys_donation_unit_cs_r_pub ( 1429 const struct DONAU_DonationUnitHashP *h_donation_unit_pub, 1430 const struct GNUNET_CRYPTO_CsSessionNonce *nonce, 1431 struct GNUNET_CRYPTO_CSPublicRPairP *r_pub) 1432 { 1433 struct DH_DonationUnitKey *dk; 1434 1435 dk = DH_keys_donation_unit_by_hash (h_donation_unit_pub); 1436 if (NULL == dk) 1437 { 1438 return TALER_EC_DONAU_GENERIC_DONATION_UNIT_UNKNOWN; 1439 } 1440 if (GNUNET_CRYPTO_BSA_CS != 1441 dk->donation_unit_pub.bsign_pub_key->cipher) 1442 { 1443 return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; 1444 } 1445 1446 { 1447 struct TALER_CRYPTO_CsDeriveRequest cdr = { 1448 .h_cs = (const struct TALER_CsPubHashP *) &dk->h_donation_unit_pub, 1449 .nonce = nonce 1450 }; 1451 return TALER_CRYPTO_helper_cs_r_batch_derive (csdh, 1452 1, 1453 &cdr, 1454 false, 1455 r_pub); 1456 } 1457 } 1458 1459 1460 /* end of donau-httpd_get-keys.c */