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