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