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