secmod_cs.c (69543B)
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; 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; 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 = htons ((uint16_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 (GNUNET_TIME_absolute_is_future (dk->anchor_start.abs_time)) 463 { 464 GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); 465 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 466 "Signing request failed, denomination key %s is not yet valid\n", 467 GNUNET_h2s (&h_cs->hash)); 468 return TALER_EC_EXCHANGE_DENOMINATION_HELPER_TOO_EARLY; 469 } 470 if (GNUNET_TIME_absolute_is_past (dk->anchor_end.abs_time)) 471 { 472 /* it is too late; now, usually we should never get here 473 as we delete upon expiration, so this is just conservative */ 474 GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); 475 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 476 "Signing request failed, denomination key %s is expired (%llu)\n", 477 GNUNET_h2s (&h_cs->hash), 478 (unsigned long long) dk->anchor_end.abs_time.abs_value_us); 479 /* usually we delete upon expiratoin, hence same EC */ 480 return TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN; 481 } 482 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 483 "Received request to sign over bytes with key %s\n", 484 GNUNET_h2s (&h_cs->hash)); 485 GNUNET_assert (dk->rc < UINT_MAX); 486 dk->rc++; 487 GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); 488 GNUNET_CRYPTO_cs_r_derive (&planchet->nonce, 489 for_melt ? "rm" : "rw", 490 &dk->denom_priv, 491 r); 492 GNUNET_CRYPTO_cs_sign_derive (&dk->denom_priv, 493 r, 494 planchet, 495 cs_sigp); 496 GNUNET_assert (0 == pthread_mutex_lock (&keys_lock)); 497 GNUNET_assert (dk->rc > 0); 498 dk->rc--; 499 GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); 500 return TALER_EC_NONE; 501 } 502 503 504 /** 505 * Generate error response that signing failed. 506 * 507 * @param client client to send response to 508 * @param ec error code to include 509 * @return #GNUNET_OK on success 510 */ 511 static enum GNUNET_GenericReturnValue 512 fail_sign (struct TES_Client *client, 513 enum TALER_ErrorCode ec) 514 { 515 struct TALER_CRYPTO_SignFailure sf = { 516 .header.size = htons (sizeof (sf)), 517 .header.type = htons (TALER_HELPER_CS_MT_RES_SIGN_FAILURE), 518 .ec = htonl (ec) 519 }; 520 521 return TES_transmit (client->csock, 522 &sf.header); 523 } 524 525 526 /** 527 * Generate error response that deriving failed. 528 * 529 * @param client client to send response to 530 * @param ec error code to include 531 * @return #GNUNET_OK on success 532 */ 533 static enum GNUNET_GenericReturnValue 534 fail_derive (struct TES_Client *client, 535 enum TALER_ErrorCode ec) 536 { 537 struct TALER_CRYPTO_RDeriveFailure sf = { 538 .header.size = htons (sizeof (sf)), 539 .header.type = htons (TALER_HELPER_CS_MT_RES_RDERIVE_FAILURE), 540 .ec = htonl (ec) 541 }; 542 543 return TES_transmit (client->csock, 544 &sf.header); 545 } 546 547 548 /** 549 * Generate signature response. 550 * 551 * @param client client to send response to 552 * @param cs_answer signature to send 553 * @return #GNUNET_OK on success 554 */ 555 static enum GNUNET_GenericReturnValue 556 send_signature (struct TES_Client *client, 557 const struct GNUNET_CRYPTO_CsBlindSignature *cs_answer) 558 { 559 struct TALER_CRYPTO_SignResponse sres; 560 561 sres.header.size = htons (sizeof (sres)); 562 sres.header.type = htons (TALER_HELPER_CS_MT_RES_SIGNATURE); 563 sres.b = htonl (cs_answer->b); 564 sres.cs_answer = cs_answer->s_scalar; 565 return TES_transmit (client->csock, 566 &sres.header); 567 } 568 569 570 /** 571 * Handle @a client request @a sr to create signature. Create the 572 * signature using the respective key and return the result to 573 * the client. 574 * 575 * @param client the client making the request 576 * @param sr the request details 577 * @return #GNUNET_OK on success 578 */ 579 static enum GNUNET_GenericReturnValue 580 handle_sign_request (struct TES_Client *client, 581 const struct TALER_CRYPTO_CsSignRequestMessage *sr) 582 { 583 struct GNUNET_CRYPTO_CsBlindSignature cs_answer; 584 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); 585 enum TALER_ErrorCode ec; 586 enum GNUNET_GenericReturnValue ret; 587 588 ec = do_sign (&sr->h_cs, 589 &sr->message, 590 (0 != ntohl (sr->for_melt)), 591 &cs_answer); 592 if (TALER_EC_NONE != ec) 593 { 594 return fail_sign (client, 595 ec); 596 } 597 ret = send_signature (client, 598 &cs_answer); 599 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 600 "Sent CS signature after %s\n", 601 GNUNET_TIME_relative2s ( 602 GNUNET_TIME_absolute_get_duration (now), 603 GNUNET_YES)); 604 return ret; 605 } 606 607 608 /** 609 * Do the actual deriving work. 610 * 611 * @param h_cs key to sign with 612 * @param nonce nonce to derive from 613 * @param for_melt true if for melting 614 * @param[out] rpairp set to the derived values 615 * @return #TALER_EC_NONE on success 616 */ 617 static enum TALER_ErrorCode 618 do_derive (const struct TALER_CsPubHashP *h_cs, 619 const struct GNUNET_CRYPTO_CsSessionNonce *nonce, 620 bool for_melt, 621 struct GNUNET_CRYPTO_CSPublicRPairP *rpairp) 622 { 623 struct DenominationKey *dk; 624 struct GNUNET_CRYPTO_CSPrivateRPairP r_priv; 625 626 GNUNET_assert (0 == pthread_mutex_lock (&keys_lock)); 627 dk = GNUNET_CONTAINER_multihashmap_get (keys, 628 &h_cs->hash); 629 if (NULL == dk) 630 { 631 GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); 632 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 633 "R Derive request failed, denomination key %s unknown\n", 634 GNUNET_h2s (&h_cs->hash)); 635 return TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN; 636 } 637 if (GNUNET_TIME_absolute_is_future (dk->anchor_start.abs_time)) 638 { 639 GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); 640 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 641 "R Derive request failed, denomination key %s is not yet valid\n", 642 GNUNET_h2s (&h_cs->hash)); 643 return TALER_EC_EXCHANGE_DENOMINATION_HELPER_TOO_EARLY; 644 } 645 if (GNUNET_TIME_absolute_is_past (dk->anchor_end.abs_time)) 646 { 647 /* it is too late; now, usually we should never get here 648 as we delete upon expiration, so this is just conservative */ 649 GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); 650 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 651 "Signing request failed, denomination key %s is expired (%llu)\n", 652 GNUNET_h2s (&h_cs->hash), 653 (unsigned long long) dk->anchor_end.abs_time.abs_value_us); 654 /* usually we delete upon expiratoin, hence same EC */ 655 return TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN; 656 } 657 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 658 "Received request to derive R with key %s\n", 659 GNUNET_h2s (&h_cs->hash)); 660 GNUNET_assert (dk->rc < UINT_MAX); 661 dk->rc++; 662 GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); 663 GNUNET_CRYPTO_cs_r_derive (nonce, 664 for_melt ? "rm" : "rw", 665 &dk->denom_priv, 666 r_priv.r); 667 GNUNET_assert (0 == pthread_mutex_lock (&keys_lock)); 668 GNUNET_assert (dk->rc > 0); 669 dk->rc--; 670 GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); 671 GNUNET_CRYPTO_cs_r_get_public (&r_priv.r[0], 672 &rpairp->r_pub[0]); 673 GNUNET_CRYPTO_cs_r_get_public (&r_priv.r[1], 674 &rpairp->r_pub[1]); 675 return TALER_EC_NONE; 676 } 677 678 679 /** 680 * Generate derivation response. 681 * 682 * @param client client to send response to 683 * @param r_pub public point value pair to send 684 * @return #GNUNET_OK on success 685 */ 686 static enum GNUNET_GenericReturnValue 687 send_derivation (struct TES_Client *client, 688 const struct GNUNET_CRYPTO_CSPublicRPairP *r_pub) 689 { 690 struct TALER_CRYPTO_RDeriveResponse rdr = { 691 .header.size = htons (sizeof (rdr)), 692 .header.type = htons (TALER_HELPER_CS_MT_RES_RDERIVE), 693 .r_pub = *r_pub 694 }; 695 696 return TES_transmit (client->csock, 697 &rdr.header); 698 } 699 700 701 /** 702 * Initialize a semaphore @a sem with a value of @a val. 703 * 704 * @param[out] sem semaphore to initialize 705 * @param val initial value of the semaphore 706 */ 707 static void 708 sem_init (struct Semaphore *sem, 709 unsigned int val) 710 { 711 GNUNET_assert (0 == 712 pthread_mutex_init (&sem->mutex, 713 NULL)); 714 GNUNET_assert (0 == 715 pthread_cond_init (&sem->cv, 716 NULL)); 717 sem->ctr = val; 718 } 719 720 721 /** 722 * Decrement semaphore, blocks until this is possible. 723 * 724 * @param[in,out] sem semaphore to decrement 725 */ 726 static void 727 sem_down (struct Semaphore *sem) 728 { 729 GNUNET_assert (0 == pthread_mutex_lock (&sem->mutex)); 730 while (0 == sem->ctr) 731 { 732 pthread_cond_wait (&sem->cv, 733 &sem->mutex); 734 } 735 sem->ctr--; 736 GNUNET_assert (0 == pthread_mutex_unlock (&sem->mutex)); 737 } 738 739 740 /** 741 * Increment semaphore, blocks until this is possible. 742 * 743 * @param[in,out] sem semaphore to decrement 744 */ 745 static void 746 sem_up (struct Semaphore *sem) 747 { 748 GNUNET_assert (0 == pthread_mutex_lock (&sem->mutex)); 749 sem->ctr++; 750 GNUNET_assert (0 == pthread_mutex_unlock (&sem->mutex)); 751 pthread_cond_signal (&sem->cv); 752 } 753 754 755 /** 756 * Release resources used by @a sem. 757 * 758 * @param[in] sem semaphore to release (except the memory itself) 759 */ 760 static void 761 sem_done (struct Semaphore *sem) 762 { 763 GNUNET_break (0 == pthread_cond_destroy (&sem->cv)); 764 GNUNET_break (0 == pthread_mutex_destroy (&sem->mutex)); 765 } 766 767 768 /** 769 * Main logic of a worker thread. Grabs work, does it, 770 * grabs more work. 771 * 772 * @param cls a `struct Worker *` 773 * @returns cls 774 */ 775 static void * 776 worker (void *cls) 777 { 778 struct Worker *w = cls; 779 780 while (true) 781 { 782 GNUNET_assert (0 == pthread_mutex_lock (&worker_lock)); 783 GNUNET_CONTAINER_DLL_insert (worker_head, 784 worker_tail, 785 w); 786 GNUNET_assert (0 == pthread_mutex_unlock (&worker_lock)); 787 sem_up (&worker_sem); 788 sem_down (&w->sem); 789 if (w->do_shutdown) 790 break; 791 { 792 struct BatchJob *bj = w->job; 793 794 switch (bj->type) 795 { 796 case TYPE_SIGN: 797 { 798 const struct TALER_CRYPTO_CsSignRequestMessage *sr 799 = bj->details.sign.sr; 800 801 bj->ec = do_sign (&sr->h_cs, 802 &sr->message, 803 (0 != ntohl (sr->for_melt)), 804 &bj->details.sign.cs_answer); 805 break; 806 } 807 case TYPE_RDERIVE: 808 { 809 const struct TALER_CRYPTO_CsRDeriveRequest *rdr 810 = bj->details.rderive.rdr; 811 bj->ec = do_derive (&rdr->h_cs, 812 &rdr->nonce, 813 (0 != ntohl (rdr->for_melt)), 814 &bj->details.rderive.rpairp); 815 break; 816 } 817 } 818 sem_up (&bj->sem); 819 w->job = NULL; 820 } 821 } 822 return w; 823 } 824 825 826 /** 827 * Start batch job @a bj to sign @a sr. 828 * 829 * @param sr signature request to answer 830 * @param[out] bj job data structure 831 */ 832 static void 833 start_sign_job (const struct TALER_CRYPTO_CsSignRequestMessage *sr, 834 struct BatchJob *bj) 835 { 836 sem_init (&bj->sem, 837 0); 838 bj->type = TYPE_SIGN; 839 bj->details.sign.sr = sr; 840 sem_down (&worker_sem); 841 GNUNET_assert (0 == pthread_mutex_lock (&worker_lock)); 842 bj->worker = worker_head; 843 GNUNET_CONTAINER_DLL_remove (worker_head, 844 worker_tail, 845 bj->worker); 846 GNUNET_assert (0 == pthread_mutex_unlock (&worker_lock)); 847 bj->worker->job = bj; 848 sem_up (&bj->worker->sem); 849 } 850 851 852 /** 853 * Start batch job @a bj to derive @a rdr. 854 * 855 * @param rdr derivation request to answer 856 * @param[out] bj job data structure 857 */ 858 static void 859 start_derive_job (const struct TALER_CRYPTO_CsRDeriveRequest *rdr, 860 struct BatchJob *bj) 861 { 862 sem_init (&bj->sem, 863 0); 864 bj->type = TYPE_RDERIVE; 865 bj->details.rderive.rdr = rdr; 866 sem_down (&worker_sem); 867 GNUNET_assert (0 == pthread_mutex_lock (&worker_lock)); 868 bj->worker = worker_head; 869 GNUNET_CONTAINER_DLL_remove (worker_head, 870 worker_tail, 871 bj->worker); 872 GNUNET_assert (0 == pthread_mutex_unlock (&worker_lock)); 873 bj->worker->job = bj; 874 sem_up (&bj->worker->sem); 875 } 876 877 878 /** 879 * Finish a job @a bj for a @a client. 880 * 881 * @param client who made the request 882 * @param[in,out] bj job to finish 883 */ 884 static void 885 finish_job (struct TES_Client *client, 886 struct BatchJob *bj) 887 { 888 sem_down (&bj->sem); 889 sem_done (&bj->sem); 890 switch (bj->type) 891 { 892 case TYPE_SIGN: 893 if (TALER_EC_NONE != bj->ec) 894 { 895 fail_sign (client, 896 bj->ec); 897 return; 898 } 899 send_signature (client, 900 &bj->details.sign.cs_answer); 901 break; 902 case TYPE_RDERIVE: 903 if (TALER_EC_NONE != bj->ec) 904 { 905 fail_derive (client, 906 bj->ec); 907 return; 908 } 909 send_derivation (client, 910 &bj->details.rderive.rpairp); 911 break; 912 } 913 } 914 915 916 /** 917 * Handle @a client request @a sr to create a batch of signature. Creates the 918 * signatures using the respective key and return the results to the client. 919 * 920 * @param client the client making the request 921 * @param bsr the request details 922 * @return #GNUNET_OK on success 923 */ 924 static enum GNUNET_GenericReturnValue 925 handle_batch_sign_request (struct TES_Client *client, 926 const struct TALER_CRYPTO_BatchSignRequest *bsr) 927 { 928 uint32_t bs = ntohl (bsr->batch_size); 929 uint16_t size = ntohs (bsr->header.size) - sizeof (*bsr); 930 const void *off = (const void *) &bsr[1]; 931 unsigned int idx = 0; 932 bool failure = false; 933 934 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 935 "Handling batch sign request of size %u\n", 936 (unsigned int) bs); 937 if (bs > TALER_MAX_COINS) 938 { 939 GNUNET_break_op (0); 940 return GNUNET_SYSERR; 941 } 942 { 943 struct BatchJob jobs[GNUNET_NZL (bs)]; 944 945 while ( (idx < bs) && 946 (size >= sizeof (struct TALER_CRYPTO_CsSignRequestMessage)) ) 947 { 948 const struct TALER_CRYPTO_CsSignRequestMessage *sr = off; 949 uint16_t s = ntohs (sr->header.size); 950 951 if (s != sizeof (*sr)) 952 { 953 failure = true; 954 bs = idx; 955 break; 956 } 957 start_sign_job (sr, 958 &jobs[idx++]); 959 off += s; 960 size -= s; 961 } 962 GNUNET_break_op (0 == size); 963 bs = GNUNET_MIN (bs, 964 idx); 965 for (unsigned int i = 0; i<bs; i++) 966 finish_job (client, 967 &jobs[i]); 968 } 969 if (failure) 970 { 971 struct TALER_CRYPTO_SignFailure sf = { 972 .header.size = htons (sizeof (sf)), 973 .header.type = htons (TALER_HELPER_CS_MT_RES_BATCH_SIGN_FAILURE), 974 .ec = htonl (TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE) 975 }; 976 977 GNUNET_break (0); 978 return TES_transmit (client->csock, 979 &sf.header); 980 } 981 return GNUNET_OK; 982 } 983 984 985 /** 986 * Handle @a client request @a sr to create a batch of derivations. Creates the 987 * derivations using the respective key and return the results to the client. 988 * 989 * @param client the client making the request 990 * @param bdr the request details 991 * @return #GNUNET_OK on success 992 */ 993 static enum GNUNET_GenericReturnValue 994 handle_batch_derive_request (struct TES_Client *client, 995 const struct TALER_CRYPTO_BatchDeriveRequest *bdr) 996 { 997 uint32_t bs = ntohl (bdr->batch_size); 998 uint16_t size = ntohs (bdr->header.size) - sizeof (*bdr); 999 const void *off = (const void *) &bdr[1]; 1000 unsigned int idx = 0; 1001 bool failure = false; 1002 1003 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1004 "Handling batch derivation request of size %u\n", 1005 (unsigned int) bs); 1006 if (bs > TALER_MAX_COINS) 1007 { 1008 GNUNET_break_op (0); 1009 return GNUNET_SYSERR; 1010 } 1011 { 1012 struct BatchJob jobs[GNUNET_NZL (bs)]; 1013 1014 while ( (idx < bs) && 1015 (size >= sizeof (struct TALER_CRYPTO_CsRDeriveRequest)) ) 1016 { 1017 const struct TALER_CRYPTO_CsRDeriveRequest *rdr = off; 1018 uint16_t s = ntohs (rdr->header.size); 1019 1020 if ( (s > size) || 1021 (s != sizeof (*rdr)) ) 1022 { 1023 failure = true; 1024 bs = idx; 1025 break; 1026 } 1027 start_derive_job (rdr, 1028 &jobs[idx++]); 1029 off += s; 1030 size -= s; 1031 } 1032 GNUNET_break_op (0 == size); 1033 bs = GNUNET_MIN (bs, 1034 idx); 1035 for (unsigned int i = 0; i<bs; i++) 1036 finish_job (client, 1037 &jobs[i]); 1038 } 1039 if (failure) 1040 { 1041 GNUNET_break (0); 1042 return fail_derive (client, 1043 TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE); 1044 } 1045 return GNUNET_OK; 1046 } 1047 1048 1049 /** 1050 * Start worker thread for batch processing. 1051 * 1052 * @return #GNUNET_OK on success 1053 */ 1054 static enum GNUNET_GenericReturnValue 1055 start_worker (void) 1056 { 1057 struct Worker *w; 1058 1059 w = GNUNET_new (struct Worker); 1060 sem_init (&w->sem, 1061 0); 1062 if (0 != pthread_create (&w->pt, 1063 NULL, 1064 &worker, 1065 w)) 1066 { 1067 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, 1068 "pthread_create"); 1069 GNUNET_free (w); 1070 return GNUNET_SYSERR; 1071 } 1072 workers++; 1073 return GNUNET_OK; 1074 } 1075 1076 1077 /** 1078 * Stop all worker threads. 1079 */ 1080 static void 1081 stop_workers (void) 1082 { 1083 while (workers > 0) 1084 { 1085 struct Worker *w; 1086 void *result; 1087 1088 sem_down (&worker_sem); 1089 GNUNET_assert (0 == pthread_mutex_lock (&worker_lock)); 1090 w = worker_head; 1091 GNUNET_CONTAINER_DLL_remove (worker_head, 1092 worker_tail, 1093 w); 1094 GNUNET_assert (0 == pthread_mutex_unlock (&worker_lock)); 1095 w->do_shutdown = true; 1096 sem_up (&w->sem); 1097 pthread_join (w->pt, 1098 &result); 1099 GNUNET_assert (result == w); 1100 sem_done (&w->sem); 1101 GNUNET_free (w); 1102 workers--; 1103 } 1104 } 1105 1106 1107 /** 1108 * Initialize key material for denomination key @a dk (also on disk). 1109 * 1110 * @param[in,out] dk denomination key to compute key material for 1111 * @param position where in the DLL will the @a dk go 1112 * @return #GNUNET_OK on success 1113 */ 1114 static enum GNUNET_GenericReturnValue 1115 setup_key (struct DenominationKey *dk, 1116 struct DenominationKey *position) 1117 { 1118 struct Denomination *denom = dk->denom; 1119 struct GNUNET_CRYPTO_CsPrivateKey priv; 1120 struct GNUNET_CRYPTO_CsPublicKey pub; 1121 1122 GNUNET_CRYPTO_cs_private_key_generate (&priv); 1123 GNUNET_CRYPTO_cs_private_key_get_public (&priv, 1124 &pub); 1125 GNUNET_CRYPTO_hash (&pub, 1126 sizeof (pub), 1127 &dk->h_cs.hash); 1128 GNUNET_asprintf ( 1129 &dk->filename, 1130 "%s/%s/%llu-%llu", 1131 keydir, 1132 denom->section, 1133 (unsigned long long) (dk->anchor_start.abs_time.abs_value_us 1134 / GNUNET_TIME_UNIT_SECONDS.rel_value_us 1135 ), 1136 (unsigned long long) (dk->anchor_end.abs_time.abs_value_us 1137 / GNUNET_TIME_UNIT_SECONDS.rel_value_us 1138 )); 1139 if (GNUNET_OK != 1140 GNUNET_DISK_fn_write (dk->filename, 1141 &priv, 1142 sizeof(priv), 1143 GNUNET_DISK_PERM_USER_READ)) 1144 { 1145 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, 1146 "write", 1147 dk->filename); 1148 return GNUNET_SYSERR; 1149 } 1150 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1151 "Setup fresh private key %s at %s in `%s' (generation #%llu)\n", 1152 GNUNET_h2s (&dk->h_cs.hash), 1153 GNUNET_TIME_timestamp2s (dk->anchor_start), 1154 dk->filename, 1155 (unsigned long long) key_gen); 1156 dk->denom_priv = priv; 1157 dk->denom_pub = pub; 1158 dk->key_gen = key_gen; 1159 generate_response (dk); 1160 if (GNUNET_OK != 1161 GNUNET_CONTAINER_multihashmap_put ( 1162 keys, 1163 &dk->h_cs.hash, 1164 dk, 1165 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) 1166 { 1167 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1168 "Duplicate private key created! Terminating.\n"); 1169 GNUNET_free (dk->filename); 1170 GNUNET_free (dk->an); 1171 GNUNET_free (dk); 1172 return GNUNET_SYSERR; 1173 } 1174 GNUNET_CONTAINER_DLL_insert_after (denom->keys_head, 1175 denom->keys_tail, 1176 position, 1177 dk); 1178 return GNUNET_OK; 1179 } 1180 1181 1182 /** 1183 * The withdraw period of a key @a dk has expired. Purge it. 1184 * 1185 * @param[in] dk expired denomination key to purge 1186 */ 1187 static void 1188 purge_key (struct DenominationKey *dk) 1189 { 1190 if (dk->purge) 1191 return; 1192 if (0 != unlink (dk->filename)) 1193 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, 1194 "unlink", 1195 dk->filename); 1196 GNUNET_free (dk->filename); 1197 dk->purge = true; 1198 dk->key_gen = key_gen; 1199 } 1200 1201 1202 /** 1203 * A @a client informs us that a key has been revoked. 1204 * Check if the key is still in use, and if so replace (!) 1205 * it with a fresh key. 1206 * 1207 * @param client the client making the request 1208 * @param rr the revocation request 1209 */ 1210 static enum GNUNET_GenericReturnValue 1211 handle_revoke_request (struct TES_Client *client, 1212 const struct TALER_CRYPTO_CsRevokeRequest *rr) 1213 { 1214 struct DenominationKey *dk; 1215 struct DenominationKey *ndk; 1216 struct Denomination *denom; 1217 1218 (void) client; 1219 GNUNET_assert (0 == pthread_mutex_lock (&keys_lock)); 1220 dk = GNUNET_CONTAINER_multihashmap_get (keys, 1221 &rr->h_cs.hash); 1222 if (NULL == dk) 1223 { 1224 GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); 1225 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 1226 "Revocation request ignored, denomination key %s unknown\n", 1227 GNUNET_h2s (&rr->h_cs.hash)); 1228 return GNUNET_OK; 1229 } 1230 if (dk->purge) 1231 { 1232 GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); 1233 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 1234 "Revocation request ignored, denomination key %s already revoked\n", 1235 GNUNET_h2s (&rr->h_cs.hash)); 1236 return GNUNET_OK; 1237 } 1238 1239 key_gen++; 1240 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1241 "Revoking key %s, bumping generation to %llu\n", 1242 GNUNET_h2s (&rr->h_cs.hash), 1243 (unsigned long long) key_gen); 1244 purge_key (dk); 1245 1246 /* Setup replacement key */ 1247 denom = dk->denom; 1248 ndk = GNUNET_new (struct DenominationKey); 1249 ndk->denom = denom; 1250 ndk->anchor_start = dk->anchor_start; 1251 ndk->anchor_end = dk->anchor_end; 1252 if (GNUNET_OK != 1253 setup_key (ndk, 1254 dk)) 1255 { 1256 GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); 1257 GNUNET_break (0); 1258 GNUNET_SCHEDULER_shutdown (); 1259 globals->global_ret = EXIT_FAILURE; 1260 return GNUNET_SYSERR; 1261 } 1262 GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); 1263 TES_wake_clients (); 1264 return GNUNET_OK; 1265 } 1266 1267 1268 /** 1269 * Handle @a client request @a rdr to create signature. Create the 1270 * signature using the respective key and return the result to 1271 * the client. 1272 * 1273 * @param client the client making the request 1274 * @param rdr the request details 1275 * @return #GNUNET_OK on success 1276 */ 1277 static enum GNUNET_GenericReturnValue 1278 handle_r_derive_request (struct TES_Client *client, 1279 const struct TALER_CRYPTO_CsRDeriveRequest *rdr) 1280 { 1281 struct GNUNET_CRYPTO_CSPublicRPairP r_pub; 1282 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); 1283 enum TALER_ErrorCode ec; 1284 enum GNUNET_GenericReturnValue ret; 1285 1286 ec = do_derive (&rdr->h_cs, 1287 &rdr->nonce, 1288 (0 != ntohl (rdr->for_melt)), 1289 &r_pub); 1290 if (TALER_EC_NONE != ec) 1291 { 1292 return fail_derive (client, 1293 ec); 1294 } 1295 1296 ret = send_derivation (client, 1297 &r_pub); 1298 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1299 "Sent CS Derived R after %s\n", 1300 GNUNET_TIME_relative2s ( 1301 GNUNET_TIME_absolute_get_duration (now), 1302 GNUNET_YES)); 1303 return ret; 1304 } 1305 1306 1307 /** 1308 * Handle @a hdr message received from @a client. 1309 * 1310 * @param client the client that received the message 1311 * @param hdr message that was received 1312 * @return #GNUNET_OK on success 1313 */ 1314 static enum GNUNET_GenericReturnValue 1315 cs_work_dispatch (struct TES_Client *client, 1316 const struct GNUNET_MessageHeader *hdr) 1317 { 1318 uint16_t msize = ntohs (hdr->size); 1319 1320 switch (ntohs (hdr->type)) 1321 { 1322 case TALER_HELPER_CS_MT_REQ_SIGN: 1323 if (msize < sizeof (struct TALER_CRYPTO_CsSignRequestMessage)) 1324 { 1325 GNUNET_break_op (0); 1326 return GNUNET_SYSERR; 1327 } 1328 return handle_sign_request ( 1329 client, 1330 (const struct TALER_CRYPTO_CsSignRequestMessage *) hdr); 1331 case TALER_HELPER_CS_MT_REQ_REVOKE: 1332 if (msize != sizeof (struct TALER_CRYPTO_CsRevokeRequest)) 1333 { 1334 GNUNET_break_op (0); 1335 return GNUNET_SYSERR; 1336 } 1337 return handle_revoke_request ( 1338 client, 1339 (const struct TALER_CRYPTO_CsRevokeRequest *) hdr); 1340 case TALER_HELPER_CS_MT_REQ_BATCH_SIGN: 1341 if (msize <= sizeof (struct TALER_CRYPTO_BatchSignRequest)) 1342 { 1343 GNUNET_break_op (0); 1344 return GNUNET_SYSERR; 1345 } 1346 return handle_batch_sign_request ( 1347 client, 1348 (const struct TALER_CRYPTO_BatchSignRequest *) hdr); 1349 case TALER_HELPER_CS_MT_REQ_BATCH_RDERIVE: 1350 if (msize <= sizeof (struct TALER_CRYPTO_BatchDeriveRequest)) 1351 { 1352 GNUNET_break_op (0); 1353 return GNUNET_SYSERR; 1354 } 1355 return handle_batch_derive_request ( 1356 client, 1357 (const struct TALER_CRYPTO_BatchDeriveRequest *) hdr); 1358 case TALER_HELPER_CS_MT_REQ_RDERIVE: 1359 if (msize != sizeof (struct TALER_CRYPTO_CsRDeriveRequest)) 1360 { 1361 GNUNET_break_op (0); 1362 return GNUNET_SYSERR; 1363 } 1364 return handle_r_derive_request (client, 1365 (const struct 1366 TALER_CRYPTO_CsRDeriveRequest *) hdr); 1367 default: 1368 GNUNET_break_op (0); 1369 return GNUNET_SYSERR; 1370 } 1371 } 1372 1373 1374 /** 1375 * Send our initial key set to @a client together with the 1376 * "sync" terminator. 1377 * 1378 * @param client the client to inform 1379 * @return #GNUNET_OK on success 1380 */ 1381 static enum GNUNET_GenericReturnValue 1382 cs_client_init (struct TES_Client *client) 1383 { 1384 size_t obs = 0; 1385 char *buf; 1386 1387 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1388 "Initializing new client %p\n", 1389 client); 1390 GNUNET_assert (0 == pthread_mutex_lock (&keys_lock)); 1391 for (struct Denomination *denom = denom_head; 1392 NULL != denom; 1393 denom = denom->next) 1394 { 1395 for (struct DenominationKey *dk = denom->keys_head; 1396 NULL != dk; 1397 dk = dk->next) 1398 { 1399 obs += ntohs (dk->an->header.size); 1400 } 1401 } 1402 buf = GNUNET_malloc (obs); 1403 obs = 0; 1404 for (struct Denomination *denom = denom_head; 1405 NULL != denom; 1406 denom = denom->next) 1407 { 1408 for (struct DenominationKey *dk = denom->keys_head; 1409 NULL != dk; 1410 dk = dk->next) 1411 { 1412 GNUNET_memcpy (&buf[obs], 1413 dk->an, 1414 ntohs (dk->an->header.size)); 1415 obs += ntohs (dk->an->header.size); 1416 } 1417 } 1418 client->key_gen = key_gen; 1419 GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); 1420 if (GNUNET_OK != 1421 TES_transmit_raw (client->csock, 1422 obs, 1423 buf)) 1424 { 1425 GNUNET_free (buf); 1426 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1427 "Client %p must have disconnected\n", 1428 client); 1429 return GNUNET_SYSERR; 1430 } 1431 GNUNET_free (buf); 1432 { 1433 struct GNUNET_MessageHeader synced = { 1434 .type = htons (TALER_HELPER_CS_SYNCED), 1435 .size = htons (sizeof (synced)) 1436 }; 1437 1438 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1439 "Sending CS SYNCED message to %p\n", 1440 client); 1441 if (GNUNET_OK != 1442 TES_transmit (client->csock, 1443 &synced)) 1444 { 1445 GNUNET_break (0); 1446 return GNUNET_SYSERR; 1447 } 1448 } 1449 return GNUNET_OK; 1450 } 1451 1452 1453 /** 1454 * Notify @a client about all changes to the keys since 1455 * the last generation known to the @a client. 1456 * 1457 * @param client the client to notify 1458 * @return #GNUNET_OK on success 1459 */ 1460 static enum GNUNET_GenericReturnValue 1461 cs_update_client_keys (struct TES_Client *client) 1462 { 1463 size_t obs = 0; 1464 char *buf; 1465 enum GNUNET_GenericReturnValue ret; 1466 1467 GNUNET_assert (0 == pthread_mutex_lock (&keys_lock)); 1468 for (struct Denomination *denom = denom_head; 1469 NULL != denom; 1470 denom = denom->next) 1471 { 1472 for (struct DenominationKey *key = denom->keys_head; 1473 NULL != key; 1474 key = key->next) 1475 { 1476 if (key->key_gen <= client->key_gen) 1477 continue; 1478 if (key->purge) 1479 obs += sizeof (struct TALER_CRYPTO_CsKeyPurgeNotification); 1480 else 1481 obs += ntohs (key->an->header.size); 1482 } 1483 } 1484 if (0 == obs) 1485 { 1486 /* nothing to do */ 1487 client->key_gen = key_gen; 1488 GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); 1489 return GNUNET_OK; 1490 } 1491 buf = GNUNET_malloc (obs); 1492 obs = 0; 1493 for (struct Denomination *denom = denom_head; 1494 NULL != denom; 1495 denom = denom->next) 1496 { 1497 for (struct DenominationKey *key = denom->keys_head; 1498 NULL != key; 1499 key = key->next) 1500 { 1501 if (key->key_gen <= client->key_gen) 1502 continue; 1503 if (key->purge) 1504 { 1505 struct TALER_CRYPTO_CsKeyPurgeNotification pn = { 1506 .header.type = htons (TALER_HELPER_CS_MT_PURGE), 1507 .header.size = htons (sizeof (pn)), 1508 .h_cs = key->h_cs 1509 }; 1510 1511 GNUNET_memcpy (&buf[obs], 1512 &pn, 1513 sizeof (pn)); 1514 GNUNET_assert (obs + sizeof (pn) 1515 > obs); 1516 obs += sizeof (pn); 1517 } 1518 else 1519 { 1520 GNUNET_memcpy (&buf[obs], 1521 key->an, 1522 ntohs (key->an->header.size)); 1523 GNUNET_assert (obs + ntohs (key->an->header.size) 1524 > obs); 1525 obs += ntohs (key->an->header.size); 1526 } 1527 } 1528 } 1529 client->key_gen = key_gen; 1530 GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); 1531 ret = TES_transmit_raw (client->csock, 1532 obs, 1533 buf); 1534 GNUNET_free (buf); 1535 return ret; 1536 } 1537 1538 1539 /** 1540 * Create a new denomination key (we do not have enough). 1541 * 1542 * @param[in,out] denom denomination key to create 1543 * @param anchor_start when to start key signing validity 1544 * @param anchor_end when to end key signing validity 1545 * @return #GNUNET_OK on success 1546 */ 1547 static enum GNUNET_GenericReturnValue 1548 create_key (struct Denomination *denom, 1549 struct GNUNET_TIME_Timestamp anchor_start, 1550 struct GNUNET_TIME_Timestamp anchor_end) 1551 { 1552 struct DenominationKey *dk; 1553 1554 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1555 "Creating new key for `%s' with start date %s\n", 1556 denom->section, 1557 GNUNET_TIME_timestamp2s (anchor_start)); 1558 dk = GNUNET_new (struct DenominationKey); 1559 dk->denom = denom; 1560 dk->anchor_start = anchor_start; 1561 dk->anchor_end = anchor_end; 1562 if (GNUNET_OK != 1563 setup_key (dk, 1564 denom->keys_tail)) 1565 { 1566 GNUNET_break (0); 1567 GNUNET_free (dk); 1568 GNUNET_SCHEDULER_shutdown (); 1569 globals->global_ret = EXIT_FAILURE; 1570 return GNUNET_SYSERR; 1571 } 1572 return GNUNET_OK; 1573 } 1574 1575 1576 /** 1577 * Obtain the maximum withdraw duration of all denominations. 1578 * 1579 * Must only be called while the #keys_lock is held. 1580 * 1581 * @return maximum withdraw duration, zero if there are no denominations 1582 */ 1583 static struct GNUNET_TIME_Relative 1584 get_maximum_duration (void) 1585 { 1586 struct GNUNET_TIME_Relative ret 1587 = GNUNET_TIME_UNIT_ZERO; 1588 1589 for (struct Denomination *denom = denom_head; 1590 NULL != denom; 1591 denom = denom->next) 1592 { 1593 ret = GNUNET_TIME_relative_max (ret, 1594 denom->duration_withdraw); 1595 } 1596 return ret; 1597 } 1598 1599 1600 /** 1601 * At what time do we need to next create keys if we just did? 1602 * 1603 * @return time when to next create keys if we just finished key generation 1604 */ 1605 static struct GNUNET_TIME_Absolute 1606 action_time (void) 1607 { 1608 struct GNUNET_TIME_Relative md = get_maximum_duration (); 1609 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); 1610 uint64_t mod; 1611 1612 if (GNUNET_TIME_relative_is_zero (md)) 1613 return GNUNET_TIME_UNIT_FOREVER_ABS; 1614 mod = now.abs_value_us % md.rel_value_us; 1615 now.abs_value_us -= mod; 1616 return GNUNET_TIME_absolute_add (now, 1617 md); 1618 } 1619 1620 1621 /** 1622 * Remove all denomination keys of @a denom that have expired. 1623 * 1624 * @param[in,out] denom denomination family to remove keys for 1625 */ 1626 static void 1627 remove_expired_denomination_keys (struct Denomination *denom) 1628 { 1629 while ( (NULL != denom->keys_head) && 1630 GNUNET_TIME_absolute_is_past ( 1631 denom->keys_head->anchor_end.abs_time) ) 1632 { 1633 struct DenominationKey *key = denom->keys_head; 1634 struct DenominationKey *nxt = key->next; 1635 1636 if (0 != key->rc) 1637 break; /* later */ 1638 GNUNET_CONTAINER_DLL_remove (denom->keys_head, 1639 denom->keys_tail, 1640 key); 1641 GNUNET_assert (GNUNET_OK == 1642 GNUNET_CONTAINER_multihashmap_remove ( 1643 keys, 1644 &key->h_cs.hash, 1645 key)); 1646 if ( (! key->purge) && 1647 (0 != unlink (key->filename)) ) 1648 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, 1649 "unlink", 1650 key->filename); 1651 GNUNET_free (key->filename); 1652 GNUNET_free (key->an); 1653 GNUNET_free (key); 1654 key = nxt; 1655 } 1656 } 1657 1658 1659 /** 1660 * Obtain the end anchor to use at this point. Uses the 1661 * #lookahead_sign and then rounds it up by the maximum 1662 * duration of any denomination to arrive at a globally 1663 * valid end-date. 1664 * 1665 * Must only be called while the #keys_lock is held. 1666 * 1667 * @return end anchor 1668 */ 1669 static struct GNUNET_TIME_Timestamp 1670 get_anchor_end (void) 1671 { 1672 struct GNUNET_TIME_Relative md = get_maximum_duration (); 1673 struct GNUNET_TIME_Absolute end 1674 = GNUNET_TIME_relative_to_absolute (lookahead_sign); 1675 uint64_t mod; 1676 1677 if (GNUNET_TIME_relative_is_zero (md)) 1678 return GNUNET_TIME_UNIT_ZERO_TS; 1679 /* Round up 'end' to a multiple of 'md' */ 1680 mod = end.abs_value_us % md.rel_value_us; 1681 end.abs_value_us -= mod; 1682 return GNUNET_TIME_absolute_to_timestamp ( 1683 GNUNET_TIME_absolute_add (end, 1684 md)); 1685 } 1686 1687 1688 /** 1689 * Create all denomination keys that are required for our 1690 * desired lookahead and that we do not yet have. 1691 * 1692 * @param[in,out] opt our options 1693 * @param[in,out] wake set to true if we should wake the clients 1694 */ 1695 static void 1696 create_missing_keys (struct TALER_SECMOD_Options *opt, 1697 bool *wake) 1698 { 1699 struct GNUNET_TIME_Timestamp start; 1700 struct GNUNET_TIME_Timestamp end; 1701 1702 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1703 "Updating denominations ...\n"); 1704 start = opt->global_now; 1705 GNUNET_assert (0 == pthread_mutex_lock (&keys_lock)); 1706 end = get_anchor_end (); 1707 for (struct Denomination *denom = denom_head; 1708 NULL != denom; 1709 denom = denom->next) 1710 { 1711 struct GNUNET_TIME_Timestamp anchor_start; 1712 struct GNUNET_TIME_Timestamp anchor_end; 1713 struct GNUNET_TIME_Timestamp next_end; 1714 bool finished = false; 1715 1716 remove_expired_denomination_keys (denom); 1717 if (NULL != denom->keys_tail) 1718 { 1719 anchor_start = denom->keys_tail->anchor_end; 1720 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1721 "Expanding keys of denomination `%s', last key %s valid for another %s\n", 1722 denom->section, 1723 GNUNET_h2s (&denom->keys_tail->h_cs.hash), 1724 GNUNET_TIME_relative2s ( 1725 GNUNET_TIME_absolute_get_remaining ( 1726 anchor_start.abs_time), 1727 true)); 1728 } 1729 else 1730 { 1731 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1732 "Starting keys of denomination `%s'\n", 1733 denom->section); 1734 /* Round the very first anchor down to the configured calendar 1735 interval; subsequent anchors inherit the alignment from the 1736 (rounded up) end of the preceding key. The UTC variants are used 1737 so that the result does not depend on the time zone the secmod 1738 happens to run in. */ 1739 anchor_start = GNUNET_TIME_absolute_to_timestamp ( 1740 GNUNET_TIME_round_down_utc (start.abs_time, 1741 denom->anchor_round)); 1742 } 1743 finished = GNUNET_TIME_timestamp_cmp (anchor_start, 1744 >=, 1745 end); 1746 while (! finished) 1747 { 1748 /* Round the end of the validity period up to the configured calendar 1749 interval. As #GNUNET_TIME_UNIT_YEARS is 365 days, this is also what 1750 keeps the anchors from drifting off the calendar boundary across leap 1751 years. Without ANCHOR_ROUND, all of this is a no-op. */ 1752 anchor_end = GNUNET_TIME_absolute_to_timestamp ( 1753 GNUNET_TIME_round_up_utc ( 1754 GNUNET_TIME_absolute_add (anchor_start.abs_time, 1755 denom->duration_withdraw), 1756 denom->anchor_round)); 1757 next_end = GNUNET_TIME_absolute_to_timestamp ( 1758 GNUNET_TIME_round_up_utc ( 1759 GNUNET_TIME_absolute_add (anchor_end.abs_time, 1760 denom->duration_withdraw), 1761 denom->anchor_round)); 1762 if (GNUNET_TIME_timestamp_cmp (next_end, 1763 >, 1764 end)) 1765 { 1766 /* With ANCHOR_ROUND set the calendar interval already provides the 1767 alignment, and stretching the last key would make it cover more 1768 than the one interval it is supposed to cover. */ 1769 if (GNUNET_TIME_RI_NONE == denom->anchor_round) 1770 anchor_end = end; /* extend period to align end periods */ 1771 finished = true; 1772 } 1773 /* adjust start time down to ensure overlap */ 1774 anchor_start = GNUNET_TIME_absolute_to_timestamp ( 1775 GNUNET_TIME_absolute_subtract (anchor_start.abs_time, 1776 overlap_duration)); 1777 if (! *wake) 1778 { 1779 key_gen++; 1780 *wake = true; 1781 } 1782 if (GNUNET_OK != 1783 create_key (denom, 1784 anchor_start, 1785 anchor_end)) 1786 { 1787 GNUNET_break (0); 1788 GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); 1789 globals->global_ret = EXIT_FAILURE; 1790 GNUNET_SCHEDULER_shutdown (); 1791 return; 1792 } 1793 anchor_start = anchor_end; 1794 } 1795 remove_expired_denomination_keys (denom); 1796 } 1797 GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); 1798 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1799 "Updating denominations finished ...\n"); 1800 } 1801 1802 1803 /** 1804 * Task run periodically to expire keys and/or generate fresh ones. 1805 * 1806 * @param cls the `struct TALER_SECMOD_Options *` 1807 */ 1808 static void 1809 update_denominations (void *cls) 1810 { 1811 struct TALER_SECMOD_Options *opt = cls; 1812 struct GNUNET_TIME_Absolute at; 1813 bool wake = false; 1814 1815 (void) cls; 1816 keygen_task = NULL; 1817 opt->global_now = GNUNET_TIME_timestamp_get (); 1818 create_missing_keys (opt, 1819 &wake); 1820 if (wake) 1821 TES_wake_clients (); 1822 at = action_time (); 1823 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1824 "Next key generation due at %s\n", 1825 GNUNET_TIME_absolute2s (at)); 1826 keygen_task = GNUNET_SCHEDULER_add_at (at, 1827 &update_denominations, 1828 opt); 1829 } 1830 1831 1832 /** 1833 * Parse private key of denomination @a denom in @a buf. 1834 * 1835 * @param[out] denom denomination of the key 1836 * @param filename name of the file we are parsing, for logging 1837 * @param priv key material 1838 */ 1839 static void 1840 parse_key (struct Denomination *denom, 1841 const char *filename, 1842 const struct GNUNET_CRYPTO_CsPrivateKey *priv) 1843 { 1844 const char *anchor_s; 1845 char dummy; 1846 unsigned long long anchor_start_ll; 1847 unsigned long long anchor_end_ll; 1848 struct GNUNET_TIME_Timestamp anchor_start; 1849 struct GNUNET_TIME_Timestamp anchor_end; 1850 char *nf = NULL; 1851 1852 anchor_s = strrchr (filename, 1853 '/'); 1854 if (NULL == anchor_s) 1855 { 1856 /* File in a directory without '/' in the name, this makes no sense. */ 1857 GNUNET_break (0); 1858 return; 1859 } 1860 anchor_s++; 1861 if (2 != sscanf (anchor_s, 1862 "%llu-%llu%c", 1863 &anchor_start_ll, 1864 &anchor_end_ll, 1865 &dummy)) 1866 { 1867 /* try legacy mode */ 1868 if (1 != sscanf (anchor_s, 1869 "%llu%c", 1870 &anchor_start_ll, 1871 &dummy)) 1872 { 1873 /* Filenames in KEYDIR must ONLY be the anchor time in seconds! */ 1874 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 1875 "Filename `%s' invalid for key file, skipping\n", 1876 anchor_s); 1877 return; 1878 } 1879 anchor_start.abs_time.abs_value_us 1880 = anchor_start_ll * GNUNET_TIME_UNIT_SECONDS.rel_value_us; 1881 if (anchor_start_ll != anchor_start.abs_time.abs_value_us 1882 / GNUNET_TIME_UNIT_SECONDS.rel_value_us) 1883 { 1884 /* Integer overflow. Bad, invalid filename. */ 1885 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 1886 "Integer overflow. Filename `%s' invalid for key file, skipping\n", 1887 anchor_s); 1888 return; 1889 } 1890 anchor_end 1891 = GNUNET_TIME_absolute_to_timestamp ( 1892 GNUNET_TIME_absolute_add (anchor_start.abs_time, 1893 denom->duration_withdraw)); 1894 GNUNET_asprintf ( 1895 &nf, 1896 "%s/%s/%llu-%llu", 1897 keydir, 1898 denom->section, 1899 anchor_start_ll, 1900 (unsigned long long) (anchor_end.abs_time.abs_value_us 1901 / GNUNET_TIME_UNIT_SECONDS.rel_value_us)); 1902 /* Try to fix the legacy filename */ 1903 if (0 != 1904 rename (filename, 1905 nf)) 1906 { 1907 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, 1908 "rename", 1909 filename); 1910 GNUNET_free (nf); 1911 } 1912 } 1913 else 1914 { 1915 anchor_start.abs_time.abs_value_us 1916 = anchor_start_ll * GNUNET_TIME_UNIT_SECONDS.rel_value_us; 1917 anchor_end.abs_time.abs_value_us 1918 = anchor_end_ll * GNUNET_TIME_UNIT_SECONDS.rel_value_us; 1919 if ( (anchor_start_ll != anchor_start.abs_time.abs_value_us 1920 / GNUNET_TIME_UNIT_SECONDS.rel_value_us) || 1921 (anchor_end_ll != anchor_end.abs_time.abs_value_us 1922 / GNUNET_TIME_UNIT_SECONDS.rel_value_us) ) 1923 { 1924 /* Integer overflow. Bad, invalid filename. */ 1925 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 1926 "Integer overflow. Filename `%s' invalid for key file, skipping\n", 1927 anchor_s); 1928 return; 1929 } 1930 } 1931 1932 { 1933 struct DenominationKey *dk; 1934 struct DenominationKey *before; 1935 1936 dk = GNUNET_new (struct DenominationKey); 1937 dk->denom_priv = *priv; 1938 dk->denom = denom; 1939 dk->anchor_start = anchor_start; 1940 dk->anchor_end = anchor_end; 1941 dk->filename = (NULL == nf) ? GNUNET_strdup (filename) : nf; 1942 GNUNET_CRYPTO_cs_private_key_get_public (priv, 1943 &dk->denom_pub); 1944 GNUNET_CRYPTO_hash (&dk->denom_pub, 1945 sizeof (dk->denom_pub), 1946 &dk->h_cs.hash); 1947 generate_response (dk); 1948 if (GNUNET_OK != 1949 GNUNET_CONTAINER_multihashmap_put ( 1950 keys, 1951 &dk->h_cs.hash, 1952 dk, 1953 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) 1954 { 1955 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1956 "Duplicate private key %s detected in file `%s'. Skipping.\n", 1957 GNUNET_h2s (&dk->h_cs.hash), 1958 filename); 1959 GNUNET_free (dk->an); 1960 GNUNET_free (dk); 1961 return; 1962 } 1963 before = NULL; 1964 for (struct DenominationKey *pos = denom->keys_head; 1965 NULL != pos; 1966 pos = pos->next) 1967 { 1968 if (GNUNET_TIME_timestamp_cmp (pos->anchor_start, 1969 >, 1970 anchor_start)) 1971 break; 1972 before = pos; 1973 } 1974 GNUNET_CONTAINER_DLL_insert_after (denom->keys_head, 1975 denom->keys_tail, 1976 before, 1977 dk); 1978 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1979 "Imported key %s from `%s'\n", 1980 GNUNET_h2s (&dk->h_cs.hash), 1981 filename); 1982 } 1983 } 1984 1985 1986 /** 1987 * Import a private key from @a filename for the denomination 1988 * given in @a cls. 1989 * 1990 * @param[in,out] cls a `struct Denomiantion` 1991 * @param filename name of a file in the directory 1992 * @return #GNUNET_OK (always, continue to iterate) 1993 */ 1994 static enum GNUNET_GenericReturnValue 1995 import_key (void *cls, 1996 const char *filename) 1997 { 1998 struct Denomination *denom = cls; 1999 struct GNUNET_DISK_FileHandle *fh; 2000 struct GNUNET_DISK_MapHandle *map; 2001 void *ptr; 2002 int fd; 2003 struct stat sbuf; 2004 2005 { 2006 struct stat lsbuf; 2007 2008 if (0 != lstat (filename, 2009 &lsbuf)) 2010 { 2011 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, 2012 "lstat", 2013 filename); 2014 return GNUNET_OK; 2015 } 2016 if (! S_ISREG (lsbuf.st_mode)) 2017 { 2018 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 2019 "File `%s' is not a regular file, which is not allowed for private keys!\n", 2020 filename); 2021 return GNUNET_OK; 2022 } 2023 } 2024 2025 fd = open (filename, 2026 O_RDONLY | O_CLOEXEC); 2027 if (-1 == fd) 2028 { 2029 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, 2030 "open", 2031 filename); 2032 return GNUNET_OK; 2033 } 2034 if (0 != fstat (fd, 2035 &sbuf)) 2036 { 2037 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, 2038 "stat", 2039 filename); 2040 GNUNET_break (0 == close (fd)); 2041 return GNUNET_OK; 2042 } 2043 if (! S_ISREG (sbuf.st_mode)) 2044 { 2045 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 2046 "File `%s' is not a regular file, which is not allowed for private keys!\n", 2047 filename); 2048 GNUNET_break (0 == close (fd)); 2049 return GNUNET_OK; 2050 } 2051 if (0 != (sbuf.st_mode & (S_IWUSR | S_IRWXG | S_IRWXO))) 2052 { 2053 /* permission are NOT tight, try to patch them up! */ 2054 if (0 != 2055 fchmod (fd, 2056 S_IRUSR)) 2057 { 2058 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, 2059 "fchmod", 2060 filename); 2061 /* refuse to use key if file has wrong permissions */ 2062 GNUNET_break (0 == close (fd)); 2063 return GNUNET_OK; 2064 } 2065 } 2066 fh = GNUNET_DISK_get_handle_from_int_fd (fd); 2067 if (NULL == fh) 2068 { 2069 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, 2070 "open", 2071 filename); 2072 GNUNET_break (0 == close (fd)); 2073 return GNUNET_OK; 2074 } 2075 if (sbuf.st_size != sizeof(struct GNUNET_CRYPTO_CsPrivateKey)) 2076 { 2077 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 2078 "File `%s' too big to be a private key\n", 2079 filename); 2080 GNUNET_DISK_file_close (fh); 2081 return GNUNET_OK; 2082 } 2083 ptr = GNUNET_DISK_file_map (fh, 2084 &map, 2085 GNUNET_DISK_MAP_TYPE_READ, 2086 (size_t) sbuf.st_size); 2087 if (NULL == ptr) 2088 { 2089 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, 2090 "mmap", 2091 filename); 2092 GNUNET_DISK_file_close (fh); 2093 return GNUNET_OK; 2094 } 2095 parse_key (denom, 2096 filename, 2097 (const struct GNUNET_CRYPTO_CsPrivateKey *) ptr); 2098 GNUNET_DISK_file_unmap (map); 2099 GNUNET_DISK_file_close (fh); 2100 return GNUNET_OK; 2101 } 2102 2103 2104 /** 2105 * Parse configuration for denomination type parameters. Also determines 2106 * our anchor by looking at the existing denominations of the same type. 2107 * 2108 * @param cfg configuration to use 2109 * @param ct section in the configuration file giving the denomination type parameters 2110 * @param[out] denom set to the denomination parameters from the configuration 2111 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the configuration is invalid 2112 */ 2113 static enum GNUNET_GenericReturnValue 2114 parse_denomination_cfg (const struct GNUNET_CONFIGURATION_Handle *cfg, 2115 const char *ct, 2116 struct Denomination *denom) 2117 { 2118 char *secname; 2119 2120 GNUNET_asprintf (&secname, 2121 "%s-secmod-cs", 2122 globals->section); 2123 if (GNUNET_OK != 2124 GNUNET_CONFIGURATION_get_value_time (cfg, 2125 ct, 2126 "DURATION_WITHDRAW", 2127 &denom->duration_withdraw)) 2128 { 2129 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 2130 ct, 2131 "DURATION_WITHDRAW"); 2132 GNUNET_free (secname); 2133 return GNUNET_SYSERR; 2134 } 2135 if (GNUNET_TIME_relative_cmp (denom->duration_withdraw, 2136 <, 2137 GNUNET_TIME_UNIT_SECONDS)) 2138 { 2139 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, 2140 ct, 2141 "DURATION_WITHDRAW", 2142 "less than one second is not supported"); 2143 GNUNET_free (secname); 2144 return GNUNET_SYSERR; 2145 } 2146 if (GNUNET_TIME_relative_cmp (overlap_duration, 2147 >=, 2148 denom->duration_withdraw)) 2149 { 2150 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, 2151 secname, 2152 "OVERLAP_DURATION", 2153 "Value given must be smaller than value for DURATION_WITHDRAW!"); 2154 GNUNET_free (secname); 2155 return GNUNET_SYSERR; 2156 } 2157 { 2158 struct GNUNET_TIME_Relative ar; 2159 2160 /* The denomination section takes precedence, the secmod section 2161 provides the default for all denominations. */ 2162 if ( (GNUNET_OK != 2163 GNUNET_CONFIGURATION_get_value_time (cfg, 2164 ct, 2165 "ANCHOR_ROUND", 2166 &ar)) && 2167 (GNUNET_OK != 2168 GNUNET_CONFIGURATION_get_value_time (cfg, 2169 secname, 2170 "ANCHOR_ROUND", 2171 &ar)) ) 2172 ar = GNUNET_TIME_UNIT_ZERO; /* not configured: do not round */ 2173 denom->anchor_round 2174 = GNUNET_TIME_relative_to_round_interval (ar); 2175 if ( (GNUNET_TIME_RI_NONE == denom->anchor_round) && 2176 (! GNUNET_TIME_relative_is_zero (ar)) ) 2177 { 2178 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, 2179 ct, 2180 "ANCHOR_ROUND", 2181 "Value given must be zero or exactly one second, minute, hour, day, week, month, quarter or year"); 2182 GNUNET_free (secname); 2183 return GNUNET_SYSERR; 2184 } 2185 } 2186 GNUNET_free (secname); 2187 denom->section = GNUNET_strdup (ct); 2188 return GNUNET_OK; 2189 } 2190 2191 2192 /** 2193 * Closure for #load_denominations. 2194 */ 2195 struct LoadContext 2196 { 2197 2198 /** 2199 * Configuration to use. 2200 */ 2201 const struct GNUNET_CONFIGURATION_Handle *cfg; 2202 2203 /** 2204 * Current time to use. 2205 */ 2206 struct GNUNET_TIME_Timestamp t; 2207 2208 /** 2209 * Status, to be set to #GNUNET_SYSERR on failure 2210 */ 2211 enum GNUNET_GenericReturnValue ret; 2212 }; 2213 2214 2215 /** 2216 * Generate new denomination signing keys for the denomination type of the given @a 2217 * denomination_alias. 2218 * 2219 * @param cls a `struct LoadContext`, with 'ret' to be set to #GNUNET_SYSERR on failure 2220 * @param denomination_alias name of the denomination's section in the configuration 2221 */ 2222 static void 2223 load_denominations (void *cls, 2224 const char *denomination_alias) 2225 { 2226 struct LoadContext *ctx = cls; 2227 struct Denomination *denom; 2228 char *cipher; 2229 2230 if ( (0 != strncasecmp (denomination_alias, 2231 "coin_", 2232 strlen ("coin_"))) && 2233 (0 != strncasecmp (denomination_alias, 2234 "coin-", 2235 strlen ("coin-"))) ) 2236 return; /* not a denomination type definition */ 2237 if (GNUNET_OK != 2238 GNUNET_CONFIGURATION_get_value_string (ctx->cfg, 2239 denomination_alias, 2240 "CIPHER", 2241 &cipher)) 2242 { 2243 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 2244 denomination_alias, 2245 "CIPHER"); 2246 return; 2247 } 2248 if (0 != strcmp (cipher, "CS")) 2249 { 2250 GNUNET_free (cipher); 2251 return; /* Ignore denominations of other types than CS*/ 2252 } 2253 GNUNET_free (cipher); 2254 2255 denom = GNUNET_new (struct Denomination); 2256 if (GNUNET_OK != 2257 parse_denomination_cfg (ctx->cfg, 2258 denomination_alias, 2259 denom)) 2260 { 2261 ctx->ret = GNUNET_SYSERR; 2262 GNUNET_free (denom); 2263 return; 2264 } 2265 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 2266 "Loading keys for denomination %s\n", 2267 denom->section); 2268 { 2269 char *dname; 2270 2271 GNUNET_asprintf (&dname, 2272 "%s/%s", 2273 keydir, 2274 denom->section); 2275 GNUNET_break (GNUNET_OK == 2276 GNUNET_DISK_directory_create (dname)); 2277 GNUNET_DISK_directory_scan (dname, 2278 &import_key, 2279 denom); 2280 GNUNET_free (dname); 2281 } 2282 GNUNET_CONTAINER_DLL_insert (denom_head, 2283 denom_tail, 2284 denom); 2285 } 2286 2287 2288 /** 2289 * Load the various duration values from @a cfg 2290 * 2291 * @param cfg configuration to use 2292 * @return #GNUNET_OK on success 2293 */ 2294 static enum GNUNET_GenericReturnValue 2295 load_durations (const struct GNUNET_CONFIGURATION_Handle *cfg) 2296 { 2297 char *secname; 2298 2299 GNUNET_asprintf (&secname, 2300 "%s-secmod-cs", 2301 globals->section); 2302 if (GNUNET_OK != 2303 GNUNET_CONFIGURATION_get_value_time (cfg, 2304 secname, 2305 "OVERLAP_DURATION", 2306 &overlap_duration)) 2307 { 2308 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 2309 secname, 2310 "OVERLAP_DURATION"); 2311 GNUNET_free (secname); 2312 return GNUNET_SYSERR; 2313 } 2314 if (GNUNET_OK != 2315 GNUNET_CONFIGURATION_get_value_time (cfg, 2316 secname, 2317 "LOOKAHEAD_SIGN", 2318 &lookahead_sign)) 2319 { 2320 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 2321 secname, 2322 "LOOKAHEAD_SIGN"); 2323 GNUNET_free (secname); 2324 return GNUNET_SYSERR; 2325 } 2326 GNUNET_free (secname); 2327 return GNUNET_OK; 2328 } 2329 2330 2331 /** 2332 * Function run on shutdown. Stops the various jobs (nicely). 2333 * 2334 * @param cls a `struct TALER_SECMOD_Options` 2335 */ 2336 static void 2337 do_shutdown (void *cls) 2338 { 2339 (void) cls; 2340 TES_listen_stop (); 2341 if (NULL != keygen_task) 2342 { 2343 GNUNET_SCHEDULER_cancel (keygen_task); 2344 keygen_task = NULL; 2345 } 2346 stop_workers (); 2347 sem_done (&worker_sem); 2348 } 2349 2350 2351 void 2352 TALER_SECMOD_cs_run (void *cls, 2353 char *const *args, 2354 const char *cfgfile, 2355 const struct GNUNET_CONFIGURATION_Handle *cfg) 2356 { 2357 static struct TES_Callbacks cb = { 2358 .dispatch = &cs_work_dispatch, 2359 .updater = &cs_update_client_keys, 2360 .init = &cs_client_init 2361 }; 2362 struct TALER_SECMOD_Options *opt = cls; 2363 char *secname; 2364 2365 (void) args; 2366 (void) cfgfile; 2367 globals = opt; 2368 if (GNUNET_TIME_timestamp_cmp (opt->global_now, 2369 !=, 2370 opt->global_now_tmp)) 2371 { 2372 /* The user gave "--now", use it! */ 2373 opt->global_now = opt->global_now_tmp; 2374 } 2375 else 2376 { 2377 /* get current time again, we may be timetraveling! */ 2378 opt->global_now = GNUNET_TIME_timestamp_get (); 2379 } 2380 GNUNET_asprintf (&secname, 2381 "%s-secmod-cs", 2382 opt->section); 2383 if (GNUNET_OK != 2384 GNUNET_CONFIGURATION_get_value_filename (cfg, 2385 secname, 2386 "KEY_DIR", 2387 &keydir)) 2388 { 2389 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 2390 secname, 2391 "KEY_DIR"); 2392 GNUNET_free (secname); 2393 opt->global_ret = EXIT_NOTCONFIGURED; 2394 return; 2395 } 2396 if (GNUNET_OK != 2397 load_durations (cfg)) 2398 { 2399 opt->global_ret = EXIT_NOTCONFIGURED; 2400 GNUNET_free (secname); 2401 return; 2402 } 2403 opt->global_ret = TES_listen_start (cfg, 2404 secname, 2405 &cb); 2406 GNUNET_free (secname); 2407 if (0 != opt->global_ret) 2408 return; 2409 sem_init (&worker_sem, 2410 0); 2411 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, 2412 opt); 2413 if (0 == opt->max_workers) 2414 { 2415 long lret; 2416 2417 lret = sysconf (_SC_NPROCESSORS_CONF); 2418 if (lret <= 0) 2419 lret = 1; 2420 opt->max_workers = (unsigned int) lret; 2421 } 2422 for (unsigned int i = 0; i<opt->max_workers; i++) 2423 if (GNUNET_OK != 2424 start_worker ()) 2425 { 2426 GNUNET_SCHEDULER_shutdown (); 2427 return; 2428 } 2429 /* Load denominations */ 2430 keys = GNUNET_CONTAINER_multihashmap_create (65536, 2431 true); 2432 { 2433 struct LoadContext lc = { 2434 .cfg = cfg, 2435 .ret = GNUNET_OK, 2436 .t = opt->global_now 2437 }; 2438 bool wake = true; 2439 2440 GNUNET_assert (0 == pthread_mutex_lock (&keys_lock)); 2441 GNUNET_CONFIGURATION_iterate_sections (cfg, 2442 &load_denominations, 2443 &lc); 2444 GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); 2445 if (GNUNET_OK != lc.ret) 2446 { 2447 opt->global_ret = EXIT_FAILURE; 2448 GNUNET_SCHEDULER_shutdown (); 2449 return; 2450 } 2451 create_missing_keys (opt, 2452 &wake); 2453 } 2454 if (NULL == denom_head) 2455 { 2456 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 2457 "No CS denominations configured. Make sure section names start with `%s' if you are using CS!\n", 2458 opt->section); 2459 TES_wake_clients (); 2460 return; 2461 } 2462 /* start job to keep keys up-to-date; MUST be run before the #listen_task, 2463 hence with priority. */ 2464 keygen_task = GNUNET_SCHEDULER_add_with_priority ( 2465 GNUNET_SCHEDULER_PRIORITY_URGENT, 2466 &update_denominations, 2467 opt); 2468 }