secmod_cs.c (69874B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2014-2026 Taler Systems SA 4 5 TALER is free software; you can redistribute it and/or modify it under the 6 terms of the GNU 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 General Public License for more details. 12 13 You should have received a copy of the GNU General Public License along with 14 TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> 15 */ 16 /** 17 * @file util/secmod_cs.c 18 * @brief Standalone process to perform private key CS operations 19 * @author Christian Grothoff 20 * 21 * Key design points: 22 * - EVERY thread of the exchange will have its own pair of connections to the 23 * crypto helpers. This way, every thread will also have its own /keys state 24 * and avoid the need to synchronize on those. 25 * - auditor signatures and master signatures are to be kept in the exchange DB, 26 * and merged with the public keys of the helper by the exchange HTTPD! 27 * - the main loop of the helper is SINGLE-THREADED, but there are 28 * threads for crypto-workers which do the signing in parallel, one per client. 29 * - thread-safety: signing happens in parallel, thus when REMOVING private keys, 30 * we must ensure that all signers are done before we fully free() the 31 * private key. This is done by reference counting (as work is always 32 * assigned and collected by the main thread). 33 */ 34 #include "platform.h" 35 #include "taler/taler_util.h" 36 #include "secmod_cs.h" 37 #include <gcrypt.h> 38 #include <pthread.h> 39 #include <sys/eventfd.h> 40 #include "taler/taler_error_codes.h" 41 #include "taler/taler_signatures.h" 42 #include "secmod_common.h" 43 #include <poll.h> 44 45 46 /** 47 * Information we keep per denomination. 48 */ 49 struct Denomination; 50 51 52 /** 53 * One particular denomination key. 54 */ 55 struct DenominationKey 56 { 57 58 /** 59 * Kept in a DLL of the respective denomination. Sorted by anchor time. 60 */ 61 struct DenominationKey *next; 62 63 /** 64 * Kept in a DLL of the respective denomination. Sorted by anchor time. 65 */ 66 struct DenominationKey *prev; 67 68 /** 69 * Denomination this key belongs to. 70 */ 71 struct Denomination *denom; 72 73 /** 74 * Name of the file this key is stored under. 75 */ 76 char *filename; 77 78 /** 79 * The private key of the denomination. 80 */ 81 struct GNUNET_CRYPTO_CsPrivateKey denom_priv; 82 83 /** 84 * The public key of the denomination. 85 */ 86 struct GNUNET_CRYPTO_CsPublicKey denom_pub; 87 88 /** 89 * Message to transmit to clients to introduce this public key. 90 */ 91 struct TALER_CRYPTO_CsKeyAvailableNotification *an; 92 93 /** 94 * Hash of this denomination's public key. 95 */ 96 struct TALER_CsPubHashP h_cs; 97 98 /** 99 * Time at which this key is supposed to become valid. 100 */ 101 struct GNUNET_TIME_Timestamp anchor_start; 102 103 /** 104 * Time at which this key is supposed to expire (exclusive). 105 */ 106 struct GNUNET_TIME_Timestamp anchor_end; 107 108 /** 109 * Generation when this key was created or revoked. 110 */ 111 uint64_t key_gen; 112 113 /** 114 * Reference counter. Counts the number of threads that are 115 * using this key at this time. 116 */ 117 unsigned int rc; 118 119 /** 120 * Flag set to true if this key has been purged and the memory 121 * must be freed as soon as @e rc hits zero. 122 */ 123 bool purge; 124 125 }; 126 127 128 struct Denomination 129 { 130 131 /** 132 * Kept in a DLL. Sorted by #denomination_action_time(). 133 */ 134 struct Denomination *next; 135 136 /** 137 * Kept in a DLL. Sorted by #denomination_action_time(). 138 */ 139 struct Denomination *prev; 140 141 /** 142 * Head of DLL of actual keys of this denomination. 143 */ 144 struct DenominationKey *keys_head; 145 146 /** 147 * Tail of DLL of actual keys of this denomination. 148 */ 149 struct DenominationKey *keys_tail; 150 151 /** 152 * How long can coins be withdrawn (generated)? Should be small 153 * enough to limit how many coins will be signed into existence with 154 * the same key, but large enough to still provide a reasonable 155 * anonymity set. 156 */ 157 struct GNUNET_TIME_Relative duration_withdraw; 158 159 /** 160 * Calendar interval the start of the validity period of our keys is 161 * rounded down to (and the end of the validity period rounded up to). 162 * #GNUNET_TIME_RI_NONE (the default) disables the rounding. Donau sets 163 * this to #GNUNET_TIME_RI_YEAR so that its keys are valid for exactly one 164 * calendar year (starting January 1st UTC), even if the key was generated 165 * in the middle of the year. 166 */ 167 enum GNUNET_TIME_RounderInterval anchor_round; 168 169 /** 170 * What is the configuration section of this denomination type? Also used 171 * for the directory name where the denomination keys are stored. 172 */ 173 char *section; 174 175 }; 176 177 178 /** 179 * A semaphore. 180 */ 181 struct Semaphore 182 { 183 /** 184 * Mutex for the semaphore. 185 */ 186 pthread_mutex_t mutex; 187 188 /** 189 * Condition variable for the semaphore. 190 */ 191 pthread_cond_t cv; 192 193 /** 194 * Counter of the semaphore. 195 */ 196 unsigned int ctr; 197 }; 198 199 200 /** 201 * Job in a batch sign request. 202 */ 203 struct BatchJob; 204 205 /** 206 * Handle for a thread that does work in batch signing. 207 */ 208 struct Worker 209 { 210 /** 211 * Kept in a DLL. 212 */ 213 struct Worker *prev; 214 215 /** 216 * Kept in a DLL. 217 */ 218 struct Worker *next; 219 220 /** 221 * Job this worker should do next. 222 */ 223 struct BatchJob *job; 224 225 /** 226 * Semaphore to signal the worker that a job is available. 227 */ 228 struct Semaphore sem; 229 230 /** 231 * Handle for this thread. 232 */ 233 pthread_t pt; 234 235 /** 236 * Set to true if the worker should terminate. 237 */ 238 bool do_shutdown; 239 }; 240 241 242 /** 243 * Job in a batch sign request. 244 */ 245 struct BatchJob 246 { 247 248 /** 249 * Thread doing the work. 250 */ 251 struct Worker *worker; 252 253 /** 254 * Semaphore to signal that the job is finished. 255 */ 256 struct Semaphore sem; 257 258 /** 259 * Computation status. 260 */ 261 enum TALER_ErrorCode ec; 262 263 /** 264 * Which type of request is this? 265 */ 266 enum { TYPE_SIGN, TYPE_RDERIVE } type; 267 268 /** 269 * Details depending on @e type. 270 */ 271 union 272 { 273 274 /** 275 * Details if @e type is TYPE_SIGN. 276 */ 277 struct 278 { 279 /** 280 * Request we are working on. 281 */ 282 const struct TALER_CRYPTO_CsSignRequestMessage *sr; 283 284 /** 285 * Result with the signature. 286 */ 287 struct GNUNET_CRYPTO_CsBlindSignature cs_answer; 288 } sign; 289 290 /** 291 * Details if type is TYPE_RDERIVE. 292 */ 293 struct 294 { 295 /** 296 * Request we are answering. 297 */ 298 const struct TALER_CRYPTO_CsRDeriveRequest *rdr; 299 300 /** 301 * Pair of points to return. 302 */ 303 struct GNUNET_CRYPTO_CSPublicRPairP rpairp; 304 305 } rderive; 306 307 } details; 308 309 }; 310 311 /** 312 * Head of DLL of workers ready for more work. 313 */ 314 static struct Worker *worker_head; 315 316 /** 317 * Tail of DLL of workers ready for more work. 318 */ 319 static struct Worker *worker_tail; 320 321 /** 322 * Lock for manipulating the worker DLL. 323 */ 324 static pthread_mutex_t worker_lock = PTHREAD_MUTEX_INITIALIZER; 325 326 /** 327 * Total number of workers that were started. 328 */ 329 static unsigned int workers; 330 331 /** 332 * Semaphore used to grab a worker. 333 */ 334 static struct Semaphore worker_sem; 335 336 /** 337 * Command-line options for various TALER_SECMOD_XXX_run() functions. 338 */ 339 static struct TALER_SECMOD_Options *globals; 340 341 /** 342 * Where do we store the keys? 343 */ 344 static char *keydir; 345 346 /** 347 * How much should coin creation (@e duration_withdraw) duration overlap 348 * with the next denomination? Basically, the starting time of two 349 * denominations is always @e duration_withdraw - #overlap_duration apart. 350 */ 351 static struct GNUNET_TIME_Relative overlap_duration; 352 353 /** 354 * How long into the future do we pre-generate keys? 355 */ 356 static struct GNUNET_TIME_Relative lookahead_sign; 357 358 /** 359 * All of our denominations, in a DLL. Sorted? 360 */ 361 static struct Denomination *denom_head; 362 363 /** 364 * All of our denominations, in a DLL. Sorted? 365 */ 366 static struct Denomination *denom_tail; 367 368 /** 369 * Map of hashes of public (CS) keys to `struct DenominationKey *` 370 * with the respective private keys. 371 */ 372 static struct GNUNET_CONTAINER_MultiHashMap *keys; 373 374 /** 375 * Task run to generate new keys. 376 */ 377 static struct GNUNET_SCHEDULER_Task *keygen_task; 378 379 /** 380 * Lock for the keys queue. 381 */ 382 static pthread_mutex_t keys_lock = PTHREAD_MUTEX_INITIALIZER; 383 384 /** 385 * Current key generation. 386 */ 387 static uint64_t key_gen; 388 389 /** 390 * Generate the announcement message for @a dk. 391 * 392 * @param[in,out] dk denomination key to generate the announcement for 393 */ 394 static void 395 generate_response (struct DenominationKey *dk) 396 { 397 struct Denomination *denom = dk->denom; 398 size_t nlen = strlen (denom->section) + 1; 399 struct TALER_CRYPTO_CsKeyAvailableNotification *an; 400 void *p; 401 size_t tlen; 402 struct GNUNET_TIME_Relative effective_duration; 403 404 GNUNET_assert (sizeof(dk->denom_pub) < UINT16_MAX); 405 GNUNET_assert (nlen < UINT16_MAX); 406 tlen = nlen + sizeof (*an); 407 GNUNET_assert (tlen < UINT16_MAX); 408 an = GNUNET_malloc (tlen); 409 an->header.size = htons ((uint16_t) tlen); 410 an->header.type = htons (TALER_HELPER_CS_MT_AVAIL); 411 an->section_name_len = htonl ((uint32_t) nlen); 412 an->anchor_time = GNUNET_TIME_timestamp_hton (dk->anchor_start); 413 effective_duration = GNUNET_TIME_absolute_get_difference ( 414 dk->anchor_start.abs_time, 415 dk->anchor_end.abs_time); 416 an->duration_withdraw = GNUNET_TIME_relative_hton (effective_duration); 417 an->denom_pub = dk->denom_pub; 418 TALER_exchange_secmod_cs_sign (&dk->h_cs, 419 denom->section, 420 dk->anchor_start, 421 effective_duration, 422 &TES_smpriv, 423 &an->secm_sig); 424 an->secm_pub = TES_smpub; 425 p = (void *) &an[1]; 426 GNUNET_memcpy (p, 427 denom->section, 428 nlen); 429 dk->an = an; 430 } 431 432 433 /** 434 * Do the actual signing work. 435 * 436 * @param h_cs hash of key to sign with 437 * @param planchet message to sign 438 * @param for_melt true if for melting 439 * @param[out] cs_sigp set to the CS signature 440 * @return #TALER_EC_NONE on success 441 */ 442 static enum TALER_ErrorCode 443 do_sign (const struct TALER_CsPubHashP *h_cs, 444 const struct GNUNET_CRYPTO_CsBlindedMessage *planchet, 445 bool for_melt, 446 struct GNUNET_CRYPTO_CsBlindSignature *cs_sigp) 447 { 448 struct GNUNET_CRYPTO_CsRSecret r[2]; 449 struct DenominationKey *dk; 450 451 GNUNET_assert (0 == pthread_mutex_lock (&keys_lock)); 452 dk = GNUNET_CONTAINER_multihashmap_get (keys, 453 &h_cs->hash); 454 if (NULL == dk) 455 { 456 GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); 457 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 458 "Signing request failed, denomination key %s unknown\n", 459 GNUNET_h2s (&h_cs->hash)); 460 return TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN; 461 } 462 if (dk->purge) 463 { 464 /* key was revoked, it must not be used for signing anymore */ 465 GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); 466 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 467 "Signing request failed, denomination key %s was revoked\n", 468 GNUNET_h2s (&h_cs->hash)); 469 return TALER_EC_EXCHANGE_GENERIC_DENOMINATION_REVOKED; 470 } 471 if (GNUNET_TIME_absolute_is_future (dk->anchor_start.abs_time)) 472 { 473 GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); 474 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 475 "Signing request failed, denomination key %s is not yet valid\n", 476 GNUNET_h2s (&h_cs->hash)); 477 return TALER_EC_EXCHANGE_DENOMINATION_HELPER_TOO_EARLY; 478 } 479 if (GNUNET_TIME_absolute_is_past (dk->anchor_end.abs_time)) 480 { 481 /* it is too late; now, usually we should never get here 482 as we delete upon expiration, so this is just conservative */ 483 GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); 484 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 485 "Signing request failed, denomination key %s is expired (%llu)\n", 486 GNUNET_h2s (&h_cs->hash), 487 (unsigned long long) dk->anchor_end.abs_time.abs_value_us); 488 /* usually we delete upon expiratoin, hence same EC */ 489 return TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN; 490 } 491 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 492 "Received request to sign over bytes with key %s\n", 493 GNUNET_h2s (&h_cs->hash)); 494 GNUNET_assert (dk->rc < UINT_MAX); 495 dk->rc++; 496 GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); 497 GNUNET_CRYPTO_cs_r_derive (&planchet->nonce, 498 for_melt ? "rm" : "rw", 499 &dk->denom_priv, 500 r); 501 GNUNET_CRYPTO_cs_sign_derive (&dk->denom_priv, 502 r, 503 planchet, 504 cs_sigp); 505 GNUNET_assert (0 == pthread_mutex_lock (&keys_lock)); 506 GNUNET_assert (dk->rc > 0); 507 dk->rc--; 508 GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); 509 return TALER_EC_NONE; 510 } 511 512 513 /** 514 * Generate error response that signing failed. 515 * 516 * @param client client to send response to 517 * @param ec error code to include 518 * @return #GNUNET_OK on success 519 */ 520 static enum GNUNET_GenericReturnValue 521 fail_sign (struct TES_Client *client, 522 enum TALER_ErrorCode ec) 523 { 524 struct TALER_CRYPTO_SignFailure sf = { 525 .header.size = htons (sizeof (sf)), 526 .header.type = htons (TALER_HELPER_CS_MT_RES_SIGN_FAILURE), 527 .ec = htonl (ec) 528 }; 529 530 return TES_transmit (client->csock, 531 &sf.header); 532 } 533 534 535 /** 536 * Generate error response that deriving failed. 537 * 538 * @param client client to send response to 539 * @param ec error code to include 540 * @return #GNUNET_OK on success 541 */ 542 static enum GNUNET_GenericReturnValue 543 fail_derive (struct TES_Client *client, 544 enum TALER_ErrorCode ec) 545 { 546 struct TALER_CRYPTO_RDeriveFailure sf = { 547 .header.size = htons (sizeof (sf)), 548 .header.type = htons (TALER_HELPER_CS_MT_RES_RDERIVE_FAILURE), 549 .ec = htonl (ec) 550 }; 551 552 return TES_transmit (client->csock, 553 &sf.header); 554 } 555 556 557 /** 558 * Generate signature response. 559 * 560 * @param client client to send response to 561 * @param cs_answer signature to send 562 * @return #GNUNET_OK on success 563 */ 564 static enum GNUNET_GenericReturnValue 565 send_signature (struct TES_Client *client, 566 const struct GNUNET_CRYPTO_CsBlindSignature *cs_answer) 567 { 568 struct TALER_CRYPTO_SignResponse sres; 569 570 sres.header.size = htons (sizeof (sres)); 571 sres.header.type = htons (TALER_HELPER_CS_MT_RES_SIGNATURE); 572 sres.b = htonl (cs_answer->b); 573 sres.cs_answer = cs_answer->s_scalar; 574 return TES_transmit (client->csock, 575 &sres.header); 576 } 577 578 579 /** 580 * Handle @a client request @a sr to create signature. Create the 581 * signature using the respective key and return the result to 582 * the client. 583 * 584 * @param client the client making the request 585 * @param sr the request details 586 * @return #GNUNET_OK on success 587 */ 588 static enum GNUNET_GenericReturnValue 589 handle_sign_request (struct TES_Client *client, 590 const struct TALER_CRYPTO_CsSignRequestMessage *sr) 591 { 592 struct GNUNET_CRYPTO_CsBlindSignature cs_answer; 593 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); 594 enum TALER_ErrorCode ec; 595 enum GNUNET_GenericReturnValue ret; 596 597 ec = do_sign (&sr->h_cs, 598 &sr->message, 599 (0 != ntohl (sr->for_melt)), 600 &cs_answer); 601 if (TALER_EC_NONE != ec) 602 { 603 return fail_sign (client, 604 ec); 605 } 606 ret = send_signature (client, 607 &cs_answer); 608 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 609 "Sent CS signature after %s\n", 610 GNUNET_TIME_relative2s ( 611 GNUNET_TIME_absolute_get_duration (now), 612 GNUNET_YES)); 613 return ret; 614 } 615 616 617 /** 618 * Do the actual deriving work. 619 * 620 * @param h_cs key to sign with 621 * @param nonce nonce to derive from 622 * @param for_melt true if for melting 623 * @param[out] rpairp set to the derived values 624 * @return #TALER_EC_NONE on success 625 */ 626 static enum TALER_ErrorCode 627 do_derive (const struct TALER_CsPubHashP *h_cs, 628 const struct GNUNET_CRYPTO_CsSessionNonce *nonce, 629 bool for_melt, 630 struct GNUNET_CRYPTO_CSPublicRPairP *rpairp) 631 { 632 struct DenominationKey *dk; 633 struct GNUNET_CRYPTO_CSPrivateRPairP r_priv; 634 635 GNUNET_assert (0 == pthread_mutex_lock (&keys_lock)); 636 dk = GNUNET_CONTAINER_multihashmap_get (keys, 637 &h_cs->hash); 638 if (NULL == dk) 639 { 640 GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); 641 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 642 "R Derive request failed, denomination key %s unknown\n", 643 GNUNET_h2s (&h_cs->hash)); 644 return TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN; 645 } 646 if (dk->purge) 647 { 648 /* key was revoked, it must not be used for deriving anymore */ 649 GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); 650 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 651 "R Derive request failed, denomination key %s was revoked\n", 652 GNUNET_h2s (&h_cs->hash)); 653 return TALER_EC_EXCHANGE_GENERIC_DENOMINATION_REVOKED; 654 } 655 if (GNUNET_TIME_absolute_is_future (dk->anchor_start.abs_time)) 656 { 657 GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); 658 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 659 "R Derive request failed, denomination key %s is not yet valid\n", 660 GNUNET_h2s (&h_cs->hash)); 661 return TALER_EC_EXCHANGE_DENOMINATION_HELPER_TOO_EARLY; 662 } 663 if (GNUNET_TIME_absolute_is_past (dk->anchor_end.abs_time)) 664 { 665 /* it is too late; now, usually we should never get here 666 as we delete upon expiration, so this is just conservative */ 667 GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); 668 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 669 "Signing request failed, denomination key %s is expired (%llu)\n", 670 GNUNET_h2s (&h_cs->hash), 671 (unsigned long long) dk->anchor_end.abs_time.abs_value_us); 672 /* usually we delete upon expiratoin, hence same EC */ 673 return TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN; 674 } 675 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 676 "Received request to derive R with key %s\n", 677 GNUNET_h2s (&h_cs->hash)); 678 GNUNET_assert (dk->rc < UINT_MAX); 679 dk->rc++; 680 GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); 681 GNUNET_CRYPTO_cs_r_derive (nonce, 682 for_melt ? "rm" : "rw", 683 &dk->denom_priv, 684 r_priv.r); 685 GNUNET_assert (0 == pthread_mutex_lock (&keys_lock)); 686 GNUNET_assert (dk->rc > 0); 687 dk->rc--; 688 GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); 689 GNUNET_CRYPTO_cs_r_get_public (&r_priv.r[0], 690 &rpairp->r_pub[0]); 691 GNUNET_CRYPTO_cs_r_get_public (&r_priv.r[1], 692 &rpairp->r_pub[1]); 693 return TALER_EC_NONE; 694 } 695 696 697 /** 698 * Generate derivation response. 699 * 700 * @param client client to send response to 701 * @param r_pub public point value pair to send 702 * @return #GNUNET_OK on success 703 */ 704 static enum GNUNET_GenericReturnValue 705 send_derivation (struct TES_Client *client, 706 const struct GNUNET_CRYPTO_CSPublicRPairP *r_pub) 707 { 708 struct TALER_CRYPTO_RDeriveResponse rdr = { 709 .header.size = htons (sizeof (rdr)), 710 .header.type = htons (TALER_HELPER_CS_MT_RES_RDERIVE), 711 .r_pub = *r_pub 712 }; 713 714 return TES_transmit (client->csock, 715 &rdr.header); 716 } 717 718 719 /** 720 * Initialize a semaphore @a sem with a value of @a val. 721 * 722 * @param[out] sem semaphore to initialize 723 * @param val initial value of the semaphore 724 */ 725 static void 726 sem_init (struct Semaphore *sem, 727 unsigned int val) 728 { 729 GNUNET_assert (0 == 730 pthread_mutex_init (&sem->mutex, 731 NULL)); 732 GNUNET_assert (0 == 733 pthread_cond_init (&sem->cv, 734 NULL)); 735 sem->ctr = val; 736 } 737 738 739 /** 740 * Decrement semaphore, blocks until this is possible. 741 * 742 * @param[in,out] sem semaphore to decrement 743 */ 744 static void 745 sem_down (struct Semaphore *sem) 746 { 747 GNUNET_assert (0 == pthread_mutex_lock (&sem->mutex)); 748 while (0 == sem->ctr) 749 { 750 pthread_cond_wait (&sem->cv, 751 &sem->mutex); 752 } 753 sem->ctr--; 754 GNUNET_assert (0 == pthread_mutex_unlock (&sem->mutex)); 755 } 756 757 758 /** 759 * Increment semaphore, blocks until this is possible. 760 * 761 * @param[in,out] sem semaphore to decrement 762 */ 763 static void 764 sem_up (struct Semaphore *sem) 765 { 766 GNUNET_assert (0 == pthread_mutex_lock (&sem->mutex)); 767 sem->ctr++; 768 pthread_cond_signal (&sem->cv); 769 GNUNET_assert (0 == pthread_mutex_unlock (&sem->mutex)); 770 } 771 772 773 /** 774 * Release resources used by @a sem. 775 * 776 * @param[in] sem semaphore to release (except the memory itself) 777 */ 778 static void 779 sem_done (struct Semaphore *sem) 780 { 781 GNUNET_break (0 == pthread_cond_destroy (&sem->cv)); 782 GNUNET_break (0 == pthread_mutex_destroy (&sem->mutex)); 783 } 784 785 786 /** 787 * Main logic of a worker thread. Grabs work, does it, 788 * grabs more work. 789 * 790 * @param cls a `struct Worker *` 791 * @returns cls 792 */ 793 static void * 794 worker (void *cls) 795 { 796 struct Worker *w = cls; 797 798 while (true) 799 { 800 GNUNET_assert (0 == pthread_mutex_lock (&worker_lock)); 801 GNUNET_CONTAINER_DLL_insert (worker_head, 802 worker_tail, 803 w); 804 GNUNET_assert (0 == pthread_mutex_unlock (&worker_lock)); 805 sem_up (&worker_sem); 806 sem_down (&w->sem); 807 if (w->do_shutdown) 808 break; 809 { 810 struct BatchJob *bj = w->job; 811 812 switch (bj->type) 813 { 814 case TYPE_SIGN: 815 { 816 const struct TALER_CRYPTO_CsSignRequestMessage *sr 817 = bj->details.sign.sr; 818 819 bj->ec = do_sign (&sr->h_cs, 820 &sr->message, 821 (0 != ntohl (sr->for_melt)), 822 &bj->details.sign.cs_answer); 823 break; 824 } 825 case TYPE_RDERIVE: 826 { 827 const struct TALER_CRYPTO_CsRDeriveRequest *rdr 828 = bj->details.rderive.rdr; 829 bj->ec = do_derive (&rdr->h_cs, 830 &rdr->nonce, 831 (0 != ntohl (rdr->for_melt)), 832 &bj->details.rderive.rpairp); 833 break; 834 } 835 } 836 sem_up (&bj->sem); 837 w->job = NULL; 838 } 839 } 840 return w; 841 } 842 843 844 /** 845 * Start batch job @a bj to sign @a sr. 846 * 847 * @param sr signature request to answer 848 * @param[out] bj job data structure 849 */ 850 static void 851 start_sign_job (const struct TALER_CRYPTO_CsSignRequestMessage *sr, 852 struct BatchJob *bj) 853 { 854 sem_init (&bj->sem, 855 0); 856 bj->type = TYPE_SIGN; 857 bj->details.sign.sr = sr; 858 sem_down (&worker_sem); 859 GNUNET_assert (0 == pthread_mutex_lock (&worker_lock)); 860 bj->worker = worker_head; 861 GNUNET_CONTAINER_DLL_remove (worker_head, 862 worker_tail, 863 bj->worker); 864 GNUNET_assert (0 == pthread_mutex_unlock (&worker_lock)); 865 bj->worker->job = bj; 866 sem_up (&bj->worker->sem); 867 } 868 869 870 /** 871 * Start batch job @a bj to derive @a rdr. 872 * 873 * @param rdr derivation request to answer 874 * @param[out] bj job data structure 875 */ 876 static void 877 start_derive_job (const struct TALER_CRYPTO_CsRDeriveRequest *rdr, 878 struct BatchJob *bj) 879 { 880 sem_init (&bj->sem, 881 0); 882 bj->type = TYPE_RDERIVE; 883 bj->details.rderive.rdr = rdr; 884 sem_down (&worker_sem); 885 GNUNET_assert (0 == pthread_mutex_lock (&worker_lock)); 886 bj->worker = worker_head; 887 GNUNET_CONTAINER_DLL_remove (worker_head, 888 worker_tail, 889 bj->worker); 890 GNUNET_assert (0 == pthread_mutex_unlock (&worker_lock)); 891 bj->worker->job = bj; 892 sem_up (&bj->worker->sem); 893 } 894 895 896 /** 897 * Finish a job @a bj for a @a client. 898 * 899 * @param client who made the request 900 * @param[in,out] bj job to finish 901 * @return #GNUNET_OK on success, #GNUNET_SYSERR if we 902 * failed to transmit the reply to @a client 903 */ 904 static enum GNUNET_GenericReturnValue 905 finish_job (struct TES_Client *client, 906 struct BatchJob *bj) 907 { 908 sem_down (&bj->sem); 909 sem_done (&bj->sem); 910 switch (bj->type) 911 { 912 case TYPE_SIGN: 913 if (TALER_EC_NONE != bj->ec) 914 return fail_sign (client, 915 bj->ec); 916 return send_signature (client, 917 &bj->details.sign.cs_answer); 918 case TYPE_RDERIVE: 919 if (TALER_EC_NONE != bj->ec) 920 return fail_derive (client, 921 bj->ec); 922 return send_derivation (client, 923 &bj->details.rderive.rpairp); 924 } 925 GNUNET_break (0); 926 return GNUNET_SYSERR; 927 } 928 929 930 /** 931 * Handle @a client request @a sr to create a batch of signature. Creates the 932 * signatures using the respective key and return the results to the client. 933 * 934 * @param client the client making the request 935 * @param bsr the request details 936 * @return #GNUNET_OK on success 937 */ 938 static enum GNUNET_GenericReturnValue 939 handle_batch_sign_request (struct TES_Client *client, 940 const struct TALER_CRYPTO_BatchSignRequest *bsr) 941 { 942 uint32_t bs = ntohl (bsr->batch_size); 943 uint16_t size = ntohs (bsr->header.size) - sizeof (*bsr); 944 const void *off = (const void *) &bsr[1]; 945 unsigned int idx = 0; 946 bool failure = false; 947 enum GNUNET_GenericReturnValue tret = GNUNET_OK; 948 949 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 950 "Handling batch sign request of size %u\n", 951 (unsigned int) bs); 952 if (bs > TALER_MAX_COINS) 953 { 954 GNUNET_break_op (0); 955 return GNUNET_SYSERR; 956 } 957 { 958 struct BatchJob jobs[GNUNET_NZL (bs)]; 959 960 while ( (idx < bs) && 961 (size >= sizeof (struct TALER_CRYPTO_CsSignRequestMessage)) ) 962 { 963 const struct TALER_CRYPTO_CsSignRequestMessage *sr = off; 964 uint16_t s = ntohs (sr->header.size); 965 966 if (s != sizeof (*sr)) 967 { 968 failure = true; 969 bs = idx; 970 break; 971 } 972 start_sign_job (sr, 973 &jobs[idx++]); 974 off += s; 975 size -= s; 976 } 977 GNUNET_break_op (0 == size); 978 bs = GNUNET_MIN (bs, 979 idx); 980 /* Note: we must finish (and thus reap) *every* job we started, 981 even once transmission failed, or we would leak workers. */ 982 for (unsigned int i = 0; i<bs; i++) 983 if (GNUNET_OK != 984 finish_job (client, 985 &jobs[i])) 986 tret = GNUNET_SYSERR; 987 } 988 if (GNUNET_OK != tret) 989 return tret; /* client is gone, do not bother with more replies */ 990 if (failure) 991 { 992 struct TALER_CRYPTO_SignFailure sf = { 993 .header.size = htons (sizeof (sf)), 994 .header.type = htons (TALER_HELPER_CS_MT_RES_BATCH_SIGN_FAILURE), 995 .ec = htonl (TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE) 996 }; 997 998 GNUNET_break (0); 999 return TES_transmit (client->csock, 1000 &sf.header); 1001 } 1002 return GNUNET_OK; 1003 } 1004 1005 1006 /** 1007 * Handle @a client request @a sr to create a batch of derivations. Creates the 1008 * derivations using the respective key and return the results to the client. 1009 * 1010 * @param client the client making the request 1011 * @param bdr the request details 1012 * @return #GNUNET_OK on success 1013 */ 1014 static enum GNUNET_GenericReturnValue 1015 handle_batch_derive_request (struct TES_Client *client, 1016 const struct TALER_CRYPTO_BatchDeriveRequest *bdr) 1017 { 1018 uint32_t bs = ntohl (bdr->batch_size); 1019 uint16_t size = ntohs (bdr->header.size) - sizeof (*bdr); 1020 const void *off = (const void *) &bdr[1]; 1021 unsigned int idx = 0; 1022 bool failure = false; 1023 enum GNUNET_GenericReturnValue tret = GNUNET_OK; 1024 1025 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1026 "Handling batch derivation request of size %u\n", 1027 (unsigned int) bs); 1028 if (bs > TALER_MAX_COINS) 1029 { 1030 GNUNET_break_op (0); 1031 return GNUNET_SYSERR; 1032 } 1033 { 1034 struct BatchJob jobs[GNUNET_NZL (bs)]; 1035 1036 while ( (idx < bs) && 1037 (size >= sizeof (struct TALER_CRYPTO_CsRDeriveRequest)) ) 1038 { 1039 const struct TALER_CRYPTO_CsRDeriveRequest *rdr = off; 1040 uint16_t s = ntohs (rdr->header.size); 1041 1042 if ( (s > size) || 1043 (s != sizeof (*rdr)) ) 1044 { 1045 failure = true; 1046 bs = idx; 1047 break; 1048 } 1049 start_derive_job (rdr, 1050 &jobs[idx++]); 1051 off += s; 1052 size -= s; 1053 } 1054 GNUNET_break_op (0 == size); 1055 bs = GNUNET_MIN (bs, 1056 idx); 1057 /* Note: we must finish (and thus reap) *every* job we started, 1058 even once transmission failed, or we would leak workers. */ 1059 for (unsigned int i = 0; i<bs; i++) 1060 if (GNUNET_OK != 1061 finish_job (client, 1062 &jobs[i])) 1063 tret = GNUNET_SYSERR; 1064 } 1065 if (GNUNET_OK != tret) 1066 return tret; /* client is gone, do not bother with more replies */ 1067 if (failure) 1068 { 1069 GNUNET_break (0); 1070 return fail_derive (client, 1071 TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE); 1072 } 1073 return GNUNET_OK; 1074 } 1075 1076 1077 /** 1078 * Start worker thread for batch processing. 1079 * 1080 * @return #GNUNET_OK on success 1081 */ 1082 static enum GNUNET_GenericReturnValue 1083 start_worker (void) 1084 { 1085 struct Worker *w; 1086 1087 w = GNUNET_new (struct Worker); 1088 sem_init (&w->sem, 1089 0); 1090 if (0 != pthread_create (&w->pt, 1091 NULL, 1092 &worker, 1093 w)) 1094 { 1095 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, 1096 "pthread_create"); 1097 GNUNET_free (w); 1098 return GNUNET_SYSERR; 1099 } 1100 workers++; 1101 return GNUNET_OK; 1102 } 1103 1104 1105 /** 1106 * Stop all worker threads. 1107 */ 1108 static void 1109 stop_workers (void) 1110 { 1111 while (workers > 0) 1112 { 1113 struct Worker *w; 1114 void *result; 1115 1116 sem_down (&worker_sem); 1117 GNUNET_assert (0 == pthread_mutex_lock (&worker_lock)); 1118 w = worker_head; 1119 GNUNET_CONTAINER_DLL_remove (worker_head, 1120 worker_tail, 1121 w); 1122 GNUNET_assert (0 == pthread_mutex_unlock (&worker_lock)); 1123 w->do_shutdown = true; 1124 sem_up (&w->sem); 1125 pthread_join (w->pt, 1126 &result); 1127 GNUNET_assert (result == w); 1128 sem_done (&w->sem); 1129 GNUNET_free (w); 1130 workers--; 1131 } 1132 } 1133 1134 1135 /** 1136 * Initialize key material for denomination key @a dk (also on disk). 1137 * 1138 * @param[in,out] dk denomination key to compute key material for 1139 * @param position where in the DLL will the @a dk go 1140 * @return #GNUNET_OK on success 1141 */ 1142 static enum GNUNET_GenericReturnValue 1143 setup_key (struct DenominationKey *dk, 1144 struct DenominationKey *position) 1145 { 1146 struct Denomination *denom = dk->denom; 1147 struct GNUNET_CRYPTO_CsPrivateKey priv; 1148 struct GNUNET_CRYPTO_CsPublicKey pub; 1149 1150 GNUNET_CRYPTO_cs_private_key_generate (&priv); 1151 GNUNET_CRYPTO_cs_private_key_get_public (&priv, 1152 &pub); 1153 GNUNET_CRYPTO_hash (&pub, 1154 sizeof (pub), 1155 &dk->h_cs.hash); 1156 GNUNET_asprintf ( 1157 &dk->filename, 1158 "%s/%s/%llu-%llu", 1159 keydir, 1160 denom->section, 1161 (unsigned long long) (dk->anchor_start.abs_time.abs_value_us 1162 / GNUNET_TIME_UNIT_SECONDS.rel_value_us 1163 ), 1164 (unsigned long long) (dk->anchor_end.abs_time.abs_value_us 1165 / GNUNET_TIME_UNIT_SECONDS.rel_value_us 1166 )); 1167 if (GNUNET_OK != 1168 GNUNET_DISK_fn_write (dk->filename, 1169 &priv, 1170 sizeof(priv), 1171 GNUNET_DISK_PERM_USER_READ)) 1172 { 1173 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, 1174 "write", 1175 dk->filename); 1176 return GNUNET_SYSERR; 1177 } 1178 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1179 "Setup fresh private key %s at %s in `%s' (generation #%llu)\n", 1180 GNUNET_h2s (&dk->h_cs.hash), 1181 GNUNET_TIME_timestamp2s (dk->anchor_start), 1182 dk->filename, 1183 (unsigned long long) key_gen); 1184 dk->denom_priv = priv; 1185 dk->denom_pub = pub; 1186 dk->key_gen = key_gen; 1187 generate_response (dk); 1188 if (GNUNET_OK != 1189 GNUNET_CONTAINER_multihashmap_put ( 1190 keys, 1191 &dk->h_cs.hash, 1192 dk, 1193 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) 1194 { 1195 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1196 "Duplicate private key created! Terminating.\n"); 1197 GNUNET_free (dk->filename); 1198 GNUNET_free (dk->an); 1199 GNUNET_free (dk); 1200 return GNUNET_SYSERR; 1201 } 1202 GNUNET_CONTAINER_DLL_insert_after (denom->keys_head, 1203 denom->keys_tail, 1204 position, 1205 dk); 1206 return GNUNET_OK; 1207 } 1208 1209 1210 /** 1211 * The withdraw period of a key @a dk has expired. Purge it. 1212 * 1213 * @param[in] dk expired denomination key to purge 1214 */ 1215 static void 1216 purge_key (struct DenominationKey *dk) 1217 { 1218 if (dk->purge) 1219 return; 1220 if (0 != unlink (dk->filename)) 1221 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, 1222 "unlink", 1223 dk->filename); 1224 GNUNET_free (dk->filename); 1225 dk->purge = true; 1226 dk->key_gen = key_gen; 1227 } 1228 1229 1230 /** 1231 * A @a client informs us that a key has been revoked. 1232 * Check if the key is still in use, and if so replace (!) 1233 * it with a fresh key. 1234 * 1235 * @param client the client making the request 1236 * @param rr the revocation request 1237 */ 1238 static enum GNUNET_GenericReturnValue 1239 handle_revoke_request (struct TES_Client *client, 1240 const struct TALER_CRYPTO_CsRevokeRequest *rr) 1241 { 1242 struct DenominationKey *dk; 1243 struct DenominationKey *ndk; 1244 struct Denomination *denom; 1245 1246 (void) client; 1247 GNUNET_assert (0 == pthread_mutex_lock (&keys_lock)); 1248 dk = GNUNET_CONTAINER_multihashmap_get (keys, 1249 &rr->h_cs.hash); 1250 if (NULL == dk) 1251 { 1252 GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); 1253 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 1254 "Revocation request ignored, denomination key %s unknown\n", 1255 GNUNET_h2s (&rr->h_cs.hash)); 1256 return GNUNET_OK; 1257 } 1258 if (dk->purge) 1259 { 1260 GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); 1261 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 1262 "Revocation request ignored, denomination key %s already revoked\n", 1263 GNUNET_h2s (&rr->h_cs.hash)); 1264 return GNUNET_OK; 1265 } 1266 1267 key_gen++; 1268 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1269 "Revoking key %s, bumping generation to %llu\n", 1270 GNUNET_h2s (&rr->h_cs.hash), 1271 (unsigned long long) key_gen); 1272 purge_key (dk); 1273 1274 /* Setup replacement key */ 1275 denom = dk->denom; 1276 ndk = GNUNET_new (struct DenominationKey); 1277 ndk->denom = denom; 1278 ndk->anchor_start = dk->anchor_start; 1279 ndk->anchor_end = dk->anchor_end; 1280 if (GNUNET_OK != 1281 setup_key (ndk, 1282 dk)) 1283 { 1284 GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); 1285 GNUNET_break (0); 1286 GNUNET_SCHEDULER_shutdown (); 1287 globals->global_ret = EXIT_FAILURE; 1288 return GNUNET_SYSERR; 1289 } 1290 GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); 1291 TES_wake_clients (); 1292 return GNUNET_OK; 1293 } 1294 1295 1296 /** 1297 * Handle @a client request @a rdr to create signature. Create the 1298 * signature using the respective key and return the result to 1299 * the client. 1300 * 1301 * @param client the client making the request 1302 * @param rdr the request details 1303 * @return #GNUNET_OK on success 1304 */ 1305 static enum GNUNET_GenericReturnValue 1306 handle_r_derive_request (struct TES_Client *client, 1307 const struct TALER_CRYPTO_CsRDeriveRequest *rdr) 1308 { 1309 struct GNUNET_CRYPTO_CSPublicRPairP r_pub; 1310 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); 1311 enum TALER_ErrorCode ec; 1312 enum GNUNET_GenericReturnValue ret; 1313 1314 ec = do_derive (&rdr->h_cs, 1315 &rdr->nonce, 1316 (0 != ntohl (rdr->for_melt)), 1317 &r_pub); 1318 if (TALER_EC_NONE != ec) 1319 { 1320 return fail_derive (client, 1321 ec); 1322 } 1323 1324 ret = send_derivation (client, 1325 &r_pub); 1326 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1327 "Sent CS Derived R after %s\n", 1328 GNUNET_TIME_relative2s ( 1329 GNUNET_TIME_absolute_get_duration (now), 1330 GNUNET_YES)); 1331 return ret; 1332 } 1333 1334 1335 /** 1336 * Handle @a hdr message received from @a client. 1337 * 1338 * @param client the client that received the message 1339 * @param hdr message that was received 1340 * @return #GNUNET_OK on success 1341 */ 1342 static enum GNUNET_GenericReturnValue 1343 cs_work_dispatch (struct TES_Client *client, 1344 const struct GNUNET_MessageHeader *hdr) 1345 { 1346 uint16_t msize = ntohs (hdr->size); 1347 1348 switch (ntohs (hdr->type)) 1349 { 1350 case TALER_HELPER_CS_MT_REQ_SIGN: 1351 if (msize < sizeof (struct TALER_CRYPTO_CsSignRequestMessage)) 1352 { 1353 GNUNET_break_op (0); 1354 return GNUNET_SYSERR; 1355 } 1356 return handle_sign_request ( 1357 client, 1358 (const struct TALER_CRYPTO_CsSignRequestMessage *) hdr); 1359 case TALER_HELPER_CS_MT_REQ_REVOKE: 1360 if (msize != sizeof (struct TALER_CRYPTO_CsRevokeRequest)) 1361 { 1362 GNUNET_break_op (0); 1363 return GNUNET_SYSERR; 1364 } 1365 return handle_revoke_request ( 1366 client, 1367 (const struct TALER_CRYPTO_CsRevokeRequest *) hdr); 1368 case TALER_HELPER_CS_MT_REQ_BATCH_SIGN: 1369 if (msize <= sizeof (struct TALER_CRYPTO_BatchSignRequest)) 1370 { 1371 GNUNET_break_op (0); 1372 return GNUNET_SYSERR; 1373 } 1374 return handle_batch_sign_request ( 1375 client, 1376 (const struct TALER_CRYPTO_BatchSignRequest *) hdr); 1377 case TALER_HELPER_CS_MT_REQ_BATCH_RDERIVE: 1378 if (msize <= sizeof (struct TALER_CRYPTO_BatchDeriveRequest)) 1379 { 1380 GNUNET_break_op (0); 1381 return GNUNET_SYSERR; 1382 } 1383 return handle_batch_derive_request ( 1384 client, 1385 (const struct TALER_CRYPTO_BatchDeriveRequest *) hdr); 1386 case TALER_HELPER_CS_MT_REQ_RDERIVE: 1387 if (msize != sizeof (struct TALER_CRYPTO_CsRDeriveRequest)) 1388 { 1389 GNUNET_break_op (0); 1390 return GNUNET_SYSERR; 1391 } 1392 return handle_r_derive_request (client, 1393 (const struct 1394 TALER_CRYPTO_CsRDeriveRequest *) hdr); 1395 default: 1396 GNUNET_break_op (0); 1397 return GNUNET_SYSERR; 1398 } 1399 } 1400 1401 1402 /** 1403 * Send our initial key set to @a client together with the 1404 * "sync" terminator. 1405 * 1406 * @param client the client to inform 1407 * @return #GNUNET_OK on success 1408 */ 1409 static enum GNUNET_GenericReturnValue 1410 cs_client_init (struct TES_Client *client) 1411 { 1412 size_t obs = 0; 1413 char *buf; 1414 1415 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1416 "Initializing new client %p\n", 1417 client); 1418 GNUNET_assert (0 == pthread_mutex_lock (&keys_lock)); 1419 for (struct Denomination *denom = denom_head; 1420 NULL != denom; 1421 denom = denom->next) 1422 { 1423 for (struct DenominationKey *dk = denom->keys_head; 1424 NULL != dk; 1425 dk = dk->next) 1426 { 1427 obs += ntohs (dk->an->header.size); 1428 } 1429 } 1430 buf = GNUNET_malloc (obs); 1431 obs = 0; 1432 for (struct Denomination *denom = denom_head; 1433 NULL != denom; 1434 denom = denom->next) 1435 { 1436 for (struct DenominationKey *dk = denom->keys_head; 1437 NULL != dk; 1438 dk = dk->next) 1439 { 1440 GNUNET_memcpy (&buf[obs], 1441 dk->an, 1442 ntohs (dk->an->header.size)); 1443 obs += ntohs (dk->an->header.size); 1444 } 1445 } 1446 client->key_gen = key_gen; 1447 GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); 1448 if (GNUNET_OK != 1449 TES_transmit_raw (client->csock, 1450 obs, 1451 buf)) 1452 { 1453 GNUNET_free (buf); 1454 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1455 "Client %p must have disconnected\n", 1456 client); 1457 return GNUNET_SYSERR; 1458 } 1459 GNUNET_free (buf); 1460 { 1461 struct GNUNET_MessageHeader synced = { 1462 .type = htons (TALER_HELPER_CS_SYNCED), 1463 .size = htons (sizeof (synced)) 1464 }; 1465 1466 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1467 "Sending CS SYNCED message to %p\n", 1468 client); 1469 if (GNUNET_OK != 1470 TES_transmit (client->csock, 1471 &synced)) 1472 { 1473 GNUNET_break (0); 1474 return GNUNET_SYSERR; 1475 } 1476 } 1477 return GNUNET_OK; 1478 } 1479 1480 1481 /** 1482 * Notify @a client about all changes to the keys since 1483 * the last generation known to the @a client. 1484 * 1485 * @param client the client to notify 1486 * @return #GNUNET_OK on success 1487 */ 1488 static enum GNUNET_GenericReturnValue 1489 cs_update_client_keys (struct TES_Client *client) 1490 { 1491 size_t obs = 0; 1492 char *buf; 1493 enum GNUNET_GenericReturnValue ret; 1494 1495 GNUNET_assert (0 == pthread_mutex_lock (&keys_lock)); 1496 for (struct Denomination *denom = denom_head; 1497 NULL != denom; 1498 denom = denom->next) 1499 { 1500 for (struct DenominationKey *key = denom->keys_head; 1501 NULL != key; 1502 key = key->next) 1503 { 1504 if (key->key_gen <= client->key_gen) 1505 continue; 1506 if (key->purge) 1507 obs += sizeof (struct TALER_CRYPTO_CsKeyPurgeNotification); 1508 else 1509 obs += ntohs (key->an->header.size); 1510 } 1511 } 1512 if (0 == obs) 1513 { 1514 /* nothing to do */ 1515 client->key_gen = key_gen; 1516 GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); 1517 return GNUNET_OK; 1518 } 1519 buf = GNUNET_malloc (obs); 1520 obs = 0; 1521 for (struct Denomination *denom = denom_head; 1522 NULL != denom; 1523 denom = denom->next) 1524 { 1525 for (struct DenominationKey *key = denom->keys_head; 1526 NULL != key; 1527 key = key->next) 1528 { 1529 if (key->key_gen <= client->key_gen) 1530 continue; 1531 if (key->purge) 1532 { 1533 struct TALER_CRYPTO_CsKeyPurgeNotification pn = { 1534 .header.type = htons (TALER_HELPER_CS_MT_PURGE), 1535 .header.size = htons (sizeof (pn)), 1536 .h_cs = key->h_cs 1537 }; 1538 1539 GNUNET_memcpy (&buf[obs], 1540 &pn, 1541 sizeof (pn)); 1542 GNUNET_assert (obs + sizeof (pn) 1543 > obs); 1544 obs += sizeof (pn); 1545 } 1546 else 1547 { 1548 GNUNET_memcpy (&buf[obs], 1549 key->an, 1550 ntohs (key->an->header.size)); 1551 GNUNET_assert (obs + ntohs (key->an->header.size) 1552 > obs); 1553 obs += ntohs (key->an->header.size); 1554 } 1555 } 1556 } 1557 client->key_gen = key_gen; 1558 GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); 1559 ret = TES_transmit_raw (client->csock, 1560 obs, 1561 buf); 1562 GNUNET_free (buf); 1563 return ret; 1564 } 1565 1566 1567 /** 1568 * Create a new denomination key (we do not have enough). 1569 * 1570 * @param[in,out] denom denomination key to create 1571 * @param anchor_start when to start key signing validity 1572 * @param anchor_end when to end key signing validity 1573 * @return #GNUNET_OK on success 1574 */ 1575 static enum GNUNET_GenericReturnValue 1576 create_key (struct Denomination *denom, 1577 struct GNUNET_TIME_Timestamp anchor_start, 1578 struct GNUNET_TIME_Timestamp anchor_end) 1579 { 1580 struct DenominationKey *dk; 1581 1582 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1583 "Creating new key for `%s' with start date %s\n", 1584 denom->section, 1585 GNUNET_TIME_timestamp2s (anchor_start)); 1586 dk = GNUNET_new (struct DenominationKey); 1587 dk->denom = denom; 1588 dk->anchor_start = anchor_start; 1589 dk->anchor_end = anchor_end; 1590 if (GNUNET_OK != 1591 setup_key (dk, 1592 denom->keys_tail)) 1593 { 1594 GNUNET_break (0); 1595 GNUNET_free (dk); 1596 GNUNET_SCHEDULER_shutdown (); 1597 globals->global_ret = EXIT_FAILURE; 1598 return GNUNET_SYSERR; 1599 } 1600 return GNUNET_OK; 1601 } 1602 1603 1604 /** 1605 * Obtain the maximum withdraw duration of all denominations. 1606 * 1607 * Must only be called while the #keys_lock is held. 1608 * 1609 * @return maximum withdraw duration, zero if there are no denominations 1610 */ 1611 static struct GNUNET_TIME_Relative 1612 get_maximum_duration (void) 1613 { 1614 struct GNUNET_TIME_Relative ret 1615 = GNUNET_TIME_UNIT_ZERO; 1616 1617 for (struct Denomination *denom = denom_head; 1618 NULL != denom; 1619 denom = denom->next) 1620 { 1621 ret = GNUNET_TIME_relative_max (ret, 1622 denom->duration_withdraw); 1623 } 1624 return ret; 1625 } 1626 1627 1628 /** 1629 * At what time do we need to next create keys if we just did? 1630 * 1631 * @return time when to next create keys if we just finished key generation 1632 */ 1633 static struct GNUNET_TIME_Absolute 1634 action_time (void) 1635 { 1636 struct GNUNET_TIME_Relative md = get_maximum_duration (); 1637 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); 1638 uint64_t mod; 1639 1640 if (GNUNET_TIME_relative_is_zero (md)) 1641 return GNUNET_TIME_UNIT_FOREVER_ABS; 1642 mod = now.abs_value_us % md.rel_value_us; 1643 now.abs_value_us -= mod; 1644 return GNUNET_TIME_absolute_add (now, 1645 md); 1646 } 1647 1648 1649 /** 1650 * Remove all denomination keys of @a denom that have expired. 1651 * 1652 * @param[in,out] denom denomination family to remove keys for 1653 */ 1654 static void 1655 remove_expired_denomination_keys (struct Denomination *denom) 1656 { 1657 while ( (NULL != denom->keys_head) && 1658 GNUNET_TIME_absolute_is_past ( 1659 denom->keys_head->anchor_end.abs_time) ) 1660 { 1661 struct DenominationKey *key = denom->keys_head; 1662 struct DenominationKey *nxt = key->next; 1663 1664 if (0 != key->rc) 1665 break; /* later */ 1666 GNUNET_CONTAINER_DLL_remove (denom->keys_head, 1667 denom->keys_tail, 1668 key); 1669 GNUNET_assert (GNUNET_OK == 1670 GNUNET_CONTAINER_multihashmap_remove ( 1671 keys, 1672 &key->h_cs.hash, 1673 key)); 1674 if ( (! key->purge) && 1675 (0 != unlink (key->filename)) ) 1676 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, 1677 "unlink", 1678 key->filename); 1679 GNUNET_free (key->filename); 1680 GNUNET_free (key->an); 1681 GNUNET_free (key); 1682 key = nxt; 1683 } 1684 } 1685 1686 1687 /** 1688 * Obtain the end anchor to use at this point. Uses the 1689 * #lookahead_sign and then rounds it up by the maximum 1690 * duration of any denomination to arrive at a globally 1691 * valid end-date. 1692 * 1693 * Must only be called while the #keys_lock is held. 1694 * 1695 * @return end anchor 1696 */ 1697 static struct GNUNET_TIME_Timestamp 1698 get_anchor_end (void) 1699 { 1700 struct GNUNET_TIME_Relative md = get_maximum_duration (); 1701 struct GNUNET_TIME_Absolute end 1702 = GNUNET_TIME_relative_to_absolute (lookahead_sign); 1703 uint64_t mod; 1704 1705 if (GNUNET_TIME_relative_is_zero (md)) 1706 return GNUNET_TIME_UNIT_ZERO_TS; 1707 /* Round up 'end' to a multiple of 'md' */ 1708 mod = end.abs_value_us % md.rel_value_us; 1709 end.abs_value_us -= mod; 1710 return GNUNET_TIME_absolute_to_timestamp ( 1711 GNUNET_TIME_absolute_add (end, 1712 md)); 1713 } 1714 1715 1716 /** 1717 * Create all denomination keys that are required for our 1718 * desired lookahead and that we do not yet have. 1719 * 1720 * @param[in,out] opt our options 1721 * @param[in,out] wake set to true if we should wake the clients 1722 */ 1723 static void 1724 create_missing_keys (struct TALER_SECMOD_Options *opt, 1725 bool *wake) 1726 { 1727 struct GNUNET_TIME_Timestamp start; 1728 struct GNUNET_TIME_Timestamp end; 1729 1730 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1731 "Updating denominations ...\n"); 1732 start = opt->global_now; 1733 GNUNET_assert (0 == pthread_mutex_lock (&keys_lock)); 1734 end = get_anchor_end (); 1735 for (struct Denomination *denom = denom_head; 1736 NULL != denom; 1737 denom = denom->next) 1738 { 1739 struct GNUNET_TIME_Timestamp anchor_start; 1740 struct GNUNET_TIME_Timestamp anchor_end; 1741 struct GNUNET_TIME_Timestamp next_end; 1742 bool finished = false; 1743 1744 remove_expired_denomination_keys (denom); 1745 if (NULL != denom->keys_tail) 1746 { 1747 anchor_start = denom->keys_tail->anchor_end; 1748 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1749 "Expanding keys of denomination `%s', last key %s valid for another %s\n", 1750 denom->section, 1751 GNUNET_h2s (&denom->keys_tail->h_cs.hash), 1752 GNUNET_TIME_relative2s ( 1753 GNUNET_TIME_absolute_get_remaining ( 1754 anchor_start.abs_time), 1755 true)); 1756 } 1757 else 1758 { 1759 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1760 "Starting keys of denomination `%s'\n", 1761 denom->section); 1762 /* Round the very first anchor down to the configured calendar 1763 interval; subsequent anchors inherit the alignment from the 1764 (rounded up) end of the preceding key. The UTC variants are used 1765 so that the result does not depend on the time zone the secmod 1766 happens to run in. */ 1767 anchor_start = GNUNET_TIME_absolute_to_timestamp ( 1768 GNUNET_TIME_round_down_utc (start.abs_time, 1769 denom->anchor_round)); 1770 } 1771 finished = GNUNET_TIME_timestamp_cmp (anchor_start, 1772 >=, 1773 end); 1774 while (! finished) 1775 { 1776 /* Round the end of the validity period up to the configured calendar 1777 interval. As #GNUNET_TIME_UNIT_YEARS is 365 days, this is also what 1778 keeps the anchors from drifting off the calendar boundary across leap 1779 years. Without ANCHOR_ROUND, all of this is a no-op. */ 1780 anchor_end = GNUNET_TIME_absolute_to_timestamp ( 1781 GNUNET_TIME_round_up_utc ( 1782 GNUNET_TIME_absolute_add (anchor_start.abs_time, 1783 denom->duration_withdraw), 1784 denom->anchor_round)); 1785 next_end = GNUNET_TIME_absolute_to_timestamp ( 1786 GNUNET_TIME_round_up_utc ( 1787 GNUNET_TIME_absolute_add (anchor_end.abs_time, 1788 denom->duration_withdraw), 1789 denom->anchor_round)); 1790 if (GNUNET_TIME_timestamp_cmp (next_end, 1791 >, 1792 end)) 1793 { 1794 /* With ANCHOR_ROUND set the calendar interval already provides the 1795 alignment, and stretching the last key would make it cover more 1796 than the one interval it is supposed to cover. */ 1797 if (GNUNET_TIME_RI_NONE == denom->anchor_round) 1798 anchor_end = end; /* extend period to align end periods */ 1799 finished = true; 1800 } 1801 /* adjust start time down to ensure overlap */ 1802 anchor_start = GNUNET_TIME_absolute_to_timestamp ( 1803 GNUNET_TIME_absolute_subtract (anchor_start.abs_time, 1804 overlap_duration)); 1805 if (! *wake) 1806 { 1807 key_gen++; 1808 *wake = true; 1809 } 1810 if (GNUNET_OK != 1811 create_key (denom, 1812 anchor_start, 1813 anchor_end)) 1814 { 1815 GNUNET_break (0); 1816 GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); 1817 globals->global_ret = EXIT_FAILURE; 1818 GNUNET_SCHEDULER_shutdown (); 1819 return; 1820 } 1821 anchor_start = anchor_end; 1822 } 1823 remove_expired_denomination_keys (denom); 1824 } 1825 GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); 1826 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1827 "Updating denominations finished ...\n"); 1828 } 1829 1830 1831 /** 1832 * Task run periodically to expire keys and/or generate fresh ones. 1833 * 1834 * @param cls the `struct TALER_SECMOD_Options *` 1835 */ 1836 static void 1837 update_denominations (void *cls) 1838 { 1839 struct TALER_SECMOD_Options *opt = cls; 1840 struct GNUNET_TIME_Absolute at; 1841 bool wake = false; 1842 1843 (void) cls; 1844 keygen_task = NULL; 1845 opt->global_now = GNUNET_TIME_timestamp_get (); 1846 create_missing_keys (opt, 1847 &wake); 1848 if (wake) 1849 TES_wake_clients (); 1850 at = action_time (); 1851 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1852 "Next key generation due at %s\n", 1853 GNUNET_TIME_absolute2s (at)); 1854 keygen_task = GNUNET_SCHEDULER_add_at (at, 1855 &update_denominations, 1856 opt); 1857 } 1858 1859 1860 /** 1861 * Parse private key of denomination @a denom in @a buf. 1862 * 1863 * @param[out] denom denomination of the key 1864 * @param filename name of the file we are parsing, for logging 1865 * @param priv key material 1866 */ 1867 static void 1868 parse_key (struct Denomination *denom, 1869 const char *filename, 1870 const struct GNUNET_CRYPTO_CsPrivateKey *priv) 1871 { 1872 const char *anchor_s; 1873 char dummy; 1874 unsigned long long anchor_start_ll; 1875 unsigned long long anchor_end_ll; 1876 struct GNUNET_TIME_Timestamp anchor_start; 1877 struct GNUNET_TIME_Timestamp anchor_end; 1878 char *nf = NULL; 1879 1880 anchor_s = strrchr (filename, 1881 '/'); 1882 if (NULL == anchor_s) 1883 { 1884 /* File in a directory without '/' in the name, this makes no sense. */ 1885 GNUNET_break (0); 1886 return; 1887 } 1888 anchor_s++; 1889 if (2 != sscanf (anchor_s, 1890 "%llu-%llu%c", 1891 &anchor_start_ll, 1892 &anchor_end_ll, 1893 &dummy)) 1894 { 1895 /* try legacy mode */ 1896 if (1 != sscanf (anchor_s, 1897 "%llu%c", 1898 &anchor_start_ll, 1899 &dummy)) 1900 { 1901 /* Filenames in KEYDIR must ONLY be the anchor time in seconds! */ 1902 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 1903 "Filename `%s' invalid for key file, skipping\n", 1904 anchor_s); 1905 return; 1906 } 1907 anchor_start.abs_time.abs_value_us 1908 = anchor_start_ll * GNUNET_TIME_UNIT_SECONDS.rel_value_us; 1909 if (anchor_start_ll != anchor_start.abs_time.abs_value_us 1910 / GNUNET_TIME_UNIT_SECONDS.rel_value_us) 1911 { 1912 /* Integer overflow. Bad, invalid filename. */ 1913 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 1914 "Integer overflow. Filename `%s' invalid for key file, skipping\n", 1915 anchor_s); 1916 return; 1917 } 1918 anchor_end 1919 = GNUNET_TIME_absolute_to_timestamp ( 1920 GNUNET_TIME_absolute_add (anchor_start.abs_time, 1921 denom->duration_withdraw)); 1922 GNUNET_asprintf ( 1923 &nf, 1924 "%s/%s/%llu-%llu", 1925 keydir, 1926 denom->section, 1927 anchor_start_ll, 1928 (unsigned long long) (anchor_end.abs_time.abs_value_us 1929 / GNUNET_TIME_UNIT_SECONDS.rel_value_us)); 1930 /* Try to fix the legacy filename */ 1931 if (0 != 1932 rename (filename, 1933 nf)) 1934 { 1935 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, 1936 "rename", 1937 filename); 1938 GNUNET_free (nf); 1939 } 1940 } 1941 else 1942 { 1943 anchor_start.abs_time.abs_value_us 1944 = anchor_start_ll * GNUNET_TIME_UNIT_SECONDS.rel_value_us; 1945 anchor_end.abs_time.abs_value_us 1946 = anchor_end_ll * GNUNET_TIME_UNIT_SECONDS.rel_value_us; 1947 if ( (anchor_start_ll != anchor_start.abs_time.abs_value_us 1948 / GNUNET_TIME_UNIT_SECONDS.rel_value_us) || 1949 (anchor_end_ll != anchor_end.abs_time.abs_value_us 1950 / GNUNET_TIME_UNIT_SECONDS.rel_value_us) ) 1951 { 1952 /* Integer overflow. Bad, invalid filename. */ 1953 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 1954 "Integer overflow. Filename `%s' invalid for key file, skipping\n", 1955 anchor_s); 1956 return; 1957 } 1958 } 1959 1960 { 1961 struct DenominationKey *dk; 1962 struct DenominationKey *before; 1963 1964 dk = GNUNET_new (struct DenominationKey); 1965 dk->denom_priv = *priv; 1966 dk->denom = denom; 1967 dk->anchor_start = anchor_start; 1968 dk->anchor_end = anchor_end; 1969 dk->filename = (NULL == nf) ? GNUNET_strdup (filename) : nf; 1970 GNUNET_CRYPTO_cs_private_key_get_public (priv, 1971 &dk->denom_pub); 1972 GNUNET_CRYPTO_hash (&dk->denom_pub, 1973 sizeof (dk->denom_pub), 1974 &dk->h_cs.hash); 1975 generate_response (dk); 1976 if (GNUNET_OK != 1977 GNUNET_CONTAINER_multihashmap_put ( 1978 keys, 1979 &dk->h_cs.hash, 1980 dk, 1981 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) 1982 { 1983 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1984 "Duplicate private key %s detected in file `%s'. Skipping.\n", 1985 GNUNET_h2s (&dk->h_cs.hash), 1986 filename); 1987 GNUNET_free (dk->an); 1988 GNUNET_free (dk); 1989 return; 1990 } 1991 before = NULL; 1992 for (struct DenominationKey *pos = denom->keys_head; 1993 NULL != pos; 1994 pos = pos->next) 1995 { 1996 if (GNUNET_TIME_timestamp_cmp (pos->anchor_start, 1997 >, 1998 anchor_start)) 1999 break; 2000 before = pos; 2001 } 2002 GNUNET_CONTAINER_DLL_insert_after (denom->keys_head, 2003 denom->keys_tail, 2004 before, 2005 dk); 2006 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 2007 "Imported key %s from `%s'\n", 2008 GNUNET_h2s (&dk->h_cs.hash), 2009 filename); 2010 } 2011 } 2012 2013 2014 /** 2015 * Import a private key from @a filename for the denomination 2016 * given in @a cls. 2017 * 2018 * @param[in,out] cls a `struct Denomiantion` 2019 * @param filename name of a file in the directory 2020 * @return #GNUNET_OK (always, continue to iterate) 2021 */ 2022 static enum GNUNET_GenericReturnValue 2023 import_key (void *cls, 2024 const char *filename) 2025 { 2026 struct Denomination *denom = cls; 2027 struct GNUNET_DISK_FileHandle *fh; 2028 struct GNUNET_DISK_MapHandle *map; 2029 void *ptr; 2030 int fd; 2031 struct stat sbuf; 2032 2033 fd = TES_open_key_file (filename, 2034 &sbuf); 2035 if (-1 == fd) 2036 return GNUNET_OK; 2037 fh = GNUNET_DISK_get_handle_from_int_fd (fd); 2038 if (NULL == fh) 2039 { 2040 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, 2041 "open", 2042 filename); 2043 GNUNET_break (0 == close (fd)); 2044 return GNUNET_OK; 2045 } 2046 if (sbuf.st_size != sizeof(struct GNUNET_CRYPTO_CsPrivateKey)) 2047 { 2048 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 2049 "File `%s' too big to be a private key\n", 2050 filename); 2051 GNUNET_DISK_file_close (fh); 2052 return GNUNET_OK; 2053 } 2054 ptr = GNUNET_DISK_file_map (fh, 2055 &map, 2056 GNUNET_DISK_MAP_TYPE_READ, 2057 (size_t) sbuf.st_size); 2058 if (NULL == ptr) 2059 { 2060 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, 2061 "mmap", 2062 filename); 2063 GNUNET_DISK_file_close (fh); 2064 return GNUNET_OK; 2065 } 2066 parse_key (denom, 2067 filename, 2068 (const struct GNUNET_CRYPTO_CsPrivateKey *) ptr); 2069 GNUNET_DISK_file_unmap (map); 2070 GNUNET_DISK_file_close (fh); 2071 return GNUNET_OK; 2072 } 2073 2074 2075 /** 2076 * Parse configuration for denomination type parameters. Also determines 2077 * our anchor by looking at the existing denominations of the same type. 2078 * 2079 * @param cfg configuration to use 2080 * @param ct section in the configuration file giving the denomination type parameters 2081 * @param[out] denom set to the denomination parameters from the configuration 2082 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the configuration is invalid 2083 */ 2084 static enum GNUNET_GenericReturnValue 2085 parse_denomination_cfg (const struct GNUNET_CONFIGURATION_Handle *cfg, 2086 const char *ct, 2087 struct Denomination *denom) 2088 { 2089 char *secname; 2090 2091 GNUNET_asprintf (&secname, 2092 "%s-secmod-cs", 2093 globals->section); 2094 if (GNUNET_OK != 2095 GNUNET_CONFIGURATION_get_value_time (cfg, 2096 ct, 2097 "DURATION_WITHDRAW", 2098 &denom->duration_withdraw)) 2099 { 2100 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 2101 ct, 2102 "DURATION_WITHDRAW"); 2103 GNUNET_free (secname); 2104 return GNUNET_SYSERR; 2105 } 2106 if (GNUNET_TIME_relative_cmp (denom->duration_withdraw, 2107 <, 2108 GNUNET_TIME_UNIT_SECONDS)) 2109 { 2110 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, 2111 ct, 2112 "DURATION_WITHDRAW", 2113 "less than one second is not supported"); 2114 GNUNET_free (secname); 2115 return GNUNET_SYSERR; 2116 } 2117 if (GNUNET_TIME_relative_cmp (overlap_duration, 2118 >=, 2119 denom->duration_withdraw)) 2120 { 2121 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, 2122 secname, 2123 "OVERLAP_DURATION", 2124 "Value given must be smaller than value for DURATION_WITHDRAW!"); 2125 GNUNET_free (secname); 2126 return GNUNET_SYSERR; 2127 } 2128 { 2129 struct GNUNET_TIME_Relative ar; 2130 2131 /* The denomination section takes precedence, the secmod section 2132 provides the default for all denominations. */ 2133 if ( (GNUNET_OK != 2134 GNUNET_CONFIGURATION_get_value_time (cfg, 2135 ct, 2136 "ANCHOR_ROUND", 2137 &ar)) && 2138 (GNUNET_OK != 2139 GNUNET_CONFIGURATION_get_value_time (cfg, 2140 secname, 2141 "ANCHOR_ROUND", 2142 &ar)) ) 2143 ar = GNUNET_TIME_UNIT_ZERO; /* not configured: do not round */ 2144 denom->anchor_round 2145 = GNUNET_TIME_relative_to_round_interval (ar); 2146 if ( (GNUNET_TIME_RI_NONE == denom->anchor_round) && 2147 (! GNUNET_TIME_relative_is_zero (ar)) ) 2148 { 2149 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, 2150 ct, 2151 "ANCHOR_ROUND", 2152 "Value given must be zero or exactly one second, minute, hour, day, week, month, quarter or year"); 2153 GNUNET_free (secname); 2154 return GNUNET_SYSERR; 2155 } 2156 } 2157 GNUNET_free (secname); 2158 denom->section = TES_normalize_section (ct); 2159 return GNUNET_OK; 2160 } 2161 2162 2163 /** 2164 * Closure for #load_denominations. 2165 */ 2166 struct LoadContext 2167 { 2168 2169 /** 2170 * Configuration to use. 2171 */ 2172 const struct GNUNET_CONFIGURATION_Handle *cfg; 2173 2174 /** 2175 * Current time to use. 2176 */ 2177 struct GNUNET_TIME_Timestamp t; 2178 2179 /** 2180 * Configuration section prefix to use for denomination settings. 2181 * "coin_" for the exchange, "doco_" for Donau. 2182 */ 2183 const char *cprefix; 2184 2185 /** 2186 * Status, to be set to #GNUNET_SYSERR on failure 2187 */ 2188 enum GNUNET_GenericReturnValue ret; 2189 }; 2190 2191 2192 /** 2193 * Generate new denomination signing keys for the denomination type of the given @a 2194 * denomination_alias. 2195 * 2196 * @param cls a `struct LoadContext`, with 'ret' to be set to #GNUNET_SYSERR on failure 2197 * @param denomination_alias name of the denomination's section in the configuration 2198 */ 2199 static void 2200 load_denominations (void *cls, 2201 const char *denomination_alias) 2202 { 2203 struct LoadContext *ctx = cls; 2204 struct Denomination *denom; 2205 char *cipher; 2206 2207 if (0 != strncasecmp (denomination_alias, 2208 ctx->cprefix, 2209 strlen (ctx->cprefix))) 2210 return; /* not a denomination type definition */ 2211 if (GNUNET_OK != 2212 GNUNET_CONFIGURATION_get_value_string (ctx->cfg, 2213 denomination_alias, 2214 "CIPHER", 2215 &cipher)) 2216 { 2217 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 2218 denomination_alias, 2219 "CIPHER"); 2220 return; 2221 } 2222 if (0 != strcmp (cipher, "CS")) 2223 { 2224 GNUNET_free (cipher); 2225 return; /* Ignore denominations of other types than CS*/ 2226 } 2227 GNUNET_free (cipher); 2228 2229 denom = GNUNET_new (struct Denomination); 2230 if (GNUNET_OK != 2231 parse_denomination_cfg (ctx->cfg, 2232 denomination_alias, 2233 denom)) 2234 { 2235 ctx->ret = GNUNET_SYSERR; 2236 GNUNET_free (denom); 2237 return; 2238 } 2239 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 2240 "Loading keys for denomination %s\n", 2241 denom->section); 2242 { 2243 char *dname; 2244 2245 GNUNET_asprintf (&dname, 2246 "%s/%s", 2247 keydir, 2248 denom->section); 2249 GNUNET_break (GNUNET_OK == 2250 GNUNET_DISK_directory_create (dname)); 2251 GNUNET_DISK_directory_scan (dname, 2252 &import_key, 2253 denom); 2254 GNUNET_free (dname); 2255 } 2256 GNUNET_CONTAINER_DLL_insert (denom_head, 2257 denom_tail, 2258 denom); 2259 } 2260 2261 2262 /** 2263 * Load the various duration values from @a cfg 2264 * 2265 * @param cfg configuration to use 2266 * @return #GNUNET_OK on success 2267 */ 2268 static enum GNUNET_GenericReturnValue 2269 load_durations (const struct GNUNET_CONFIGURATION_Handle *cfg) 2270 { 2271 char *secname; 2272 2273 GNUNET_asprintf (&secname, 2274 "%s-secmod-cs", 2275 globals->section); 2276 if (GNUNET_OK != 2277 GNUNET_CONFIGURATION_get_value_time (cfg, 2278 secname, 2279 "OVERLAP_DURATION", 2280 &overlap_duration)) 2281 { 2282 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 2283 secname, 2284 "OVERLAP_DURATION"); 2285 GNUNET_free (secname); 2286 return GNUNET_SYSERR; 2287 } 2288 if (GNUNET_OK != 2289 GNUNET_CONFIGURATION_get_value_time (cfg, 2290 secname, 2291 "LOOKAHEAD_SIGN", 2292 &lookahead_sign)) 2293 { 2294 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 2295 secname, 2296 "LOOKAHEAD_SIGN"); 2297 GNUNET_free (secname); 2298 return GNUNET_SYSERR; 2299 } 2300 GNUNET_free (secname); 2301 return GNUNET_OK; 2302 } 2303 2304 2305 /** 2306 * Function run on shutdown. Stops the various jobs (nicely). 2307 * 2308 * @param cls a `struct TALER_SECMOD_Options` 2309 */ 2310 static void 2311 do_shutdown (void *cls) 2312 { 2313 (void) cls; 2314 TES_listen_stop (); 2315 if (NULL != keygen_task) 2316 { 2317 GNUNET_SCHEDULER_cancel (keygen_task); 2318 keygen_task = NULL; 2319 } 2320 stop_workers (); 2321 sem_done (&worker_sem); 2322 } 2323 2324 2325 void 2326 TALER_SECMOD_cs_run (void *cls, 2327 char *const *args, 2328 const char *cfgfile, 2329 const struct GNUNET_CONFIGURATION_Handle *cfg) 2330 { 2331 static struct TES_Callbacks cb = { 2332 .dispatch = &cs_work_dispatch, 2333 .updater = &cs_update_client_keys, 2334 .init = &cs_client_init 2335 }; 2336 struct TALER_SECMOD_Options *opt = cls; 2337 char *secname; 2338 2339 (void) args; 2340 (void) cfgfile; 2341 globals = opt; 2342 if (GNUNET_TIME_timestamp_cmp (opt->global_now, 2343 !=, 2344 opt->global_now_tmp)) 2345 { 2346 /* The user gave "--now", use it! */ 2347 opt->global_now = opt->global_now_tmp; 2348 } 2349 else 2350 { 2351 /* get current time again, we may be timetraveling! */ 2352 opt->global_now = GNUNET_TIME_timestamp_get (); 2353 } 2354 GNUNET_asprintf (&secname, 2355 "%s-secmod-cs", 2356 opt->section); 2357 if (GNUNET_OK != 2358 GNUNET_CONFIGURATION_get_value_filename (cfg, 2359 secname, 2360 "KEY_DIR", 2361 &keydir)) 2362 { 2363 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 2364 secname, 2365 "KEY_DIR"); 2366 GNUNET_free (secname); 2367 opt->global_ret = EXIT_NOTCONFIGURED; 2368 return; 2369 } 2370 if (GNUNET_OK != 2371 load_durations (cfg)) 2372 { 2373 opt->global_ret = EXIT_NOTCONFIGURED; 2374 GNUNET_free (secname); 2375 return; 2376 } 2377 if (GNUNET_OK != 2378 TES_normalize_key_directory (cfg, 2379 keydir, 2380 opt->cprefix)) 2381 { 2382 opt->global_ret = EXIT_FAILURE; 2383 GNUNET_free (secname); 2384 return; 2385 } 2386 opt->global_ret = TES_listen_start (cfg, 2387 secname, 2388 &cb); 2389 GNUNET_free (secname); 2390 if (0 != opt->global_ret) 2391 return; 2392 sem_init (&worker_sem, 2393 0); 2394 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, 2395 opt); 2396 if (0 == opt->max_workers) 2397 { 2398 long lret; 2399 2400 lret = sysconf (_SC_NPROCESSORS_CONF); 2401 if (lret <= 0) 2402 lret = 1; 2403 opt->max_workers = (unsigned int) lret; 2404 } 2405 for (unsigned int i = 0; i<opt->max_workers; i++) 2406 if (GNUNET_OK != 2407 start_worker ()) 2408 { 2409 GNUNET_SCHEDULER_shutdown (); 2410 return; 2411 } 2412 /* Load denominations */ 2413 keys = GNUNET_CONTAINER_multihashmap_create (65536, 2414 true); 2415 { 2416 struct LoadContext lc = { 2417 .cfg = cfg, 2418 .ret = GNUNET_OK, 2419 .t = opt->global_now, 2420 .cprefix = opt->cprefix 2421 }; 2422 bool wake = true; 2423 2424 GNUNET_assert (0 == pthread_mutex_lock (&keys_lock)); 2425 GNUNET_CONFIGURATION_iterate_sections (cfg, 2426 &load_denominations, 2427 &lc); 2428 GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); 2429 if (GNUNET_OK != lc.ret) 2430 { 2431 opt->global_ret = EXIT_FAILURE; 2432 GNUNET_SCHEDULER_shutdown (); 2433 return; 2434 } 2435 create_missing_keys (opt, 2436 &wake); 2437 } 2438 if (NULL == denom_head) 2439 { 2440 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 2441 "No CS denominations configured. Make sure section names start with `%s' if you are using CS!\n", 2442 opt->cprefix); 2443 TES_wake_clients (); 2444 return; 2445 } 2446 /* start job to keep keys up-to-date; MUST be run before the #listen_task, 2447 hence with priority. */ 2448 keygen_task = GNUNET_SCHEDULER_add_with_priority ( 2449 GNUNET_SCHEDULER_PRIORITY_URGENT, 2450 &update_denominations, 2451 opt); 2452 }