secmod_cs.c (66365B)
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 "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_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 struct BatchJob jobs[GNUNET_NZL (bs)]; 923 bool failure = false; 924 925 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 926 "Handling batch sign request of size %u\n", 927 (unsigned int) bs); 928 if (bs > TALER_MAX_COINS) 929 { 930 GNUNET_break_op (0); 931 return GNUNET_SYSERR; 932 } 933 while ( (bs > 0) && 934 (size >= sizeof (struct TALER_CRYPTO_CsSignRequestMessage)) ) 935 { 936 const struct TALER_CRYPTO_CsSignRequestMessage *sr = off; 937 uint16_t s = ntohs (sr->header.size); 938 939 if (s > size) 940 { 941 failure = true; 942 bs = idx; 943 break; 944 } 945 start_sign_job (sr, 946 &jobs[idx++]); 947 off += s; 948 size -= s; 949 } 950 GNUNET_break_op (0 == size); 951 bs = GNUNET_MIN (bs, 952 idx); 953 for (unsigned int i = 0; i<bs; i++) 954 finish_job (client, 955 &jobs[i]); 956 if (failure) 957 { 958 struct TALER_CRYPTO_SignFailure sf = { 959 .header.size = htons (sizeof (sf)), 960 .header.type = htons (TALER_HELPER_CS_MT_RES_BATCH_SIGN_FAILURE), 961 .ec = htonl (TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE) 962 }; 963 964 GNUNET_break (0); 965 return TES_transmit (client->csock, 966 &sf.header); 967 } 968 return GNUNET_OK; 969 } 970 971 972 /** 973 * Handle @a client request @a sr to create a batch of derivations. Creates the 974 * derivations using the respective key and return the results to the client. 975 * 976 * @param client the client making the request 977 * @param bdr the request details 978 * @return #GNUNET_OK on success 979 */ 980 static enum GNUNET_GenericReturnValue 981 handle_batch_derive_request (struct TES_Client *client, 982 const struct TALER_CRYPTO_BatchDeriveRequest *bdr) 983 { 984 uint32_t bs = ntohl (bdr->batch_size); 985 uint16_t size = ntohs (bdr->header.size) - sizeof (*bdr); 986 const void *off = (const void *) &bdr[1]; 987 unsigned int idx = 0; 988 struct BatchJob jobs[bs]; 989 bool failure = false; 990 991 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 992 "Handling batch derivation request of size %u\n", 993 (unsigned int) bs); 994 if (bs > TALER_MAX_COINS) 995 { 996 GNUNET_break_op (0); 997 return GNUNET_SYSERR; 998 } 999 while ( (bs > 0) && 1000 (size >= sizeof (struct TALER_CRYPTO_CsRDeriveRequest)) ) 1001 { 1002 const struct TALER_CRYPTO_CsRDeriveRequest *rdr = off; 1003 uint16_t s = ntohs (rdr->header.size); 1004 1005 if ( (s > size) || 1006 (s != sizeof (*rdr)) ) 1007 { 1008 failure = true; 1009 bs = idx; 1010 break; 1011 } 1012 start_derive_job (rdr, 1013 &jobs[idx++]); 1014 off += s; 1015 size -= s; 1016 } 1017 GNUNET_break_op (0 == size); 1018 bs = GNUNET_MIN (bs, 1019 idx); 1020 for (unsigned int i = 0; i<bs; i++) 1021 finish_job (client, 1022 &jobs[i]); 1023 if (failure) 1024 { 1025 GNUNET_break (0); 1026 return fail_derive (client, 1027 TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE); 1028 } 1029 return GNUNET_OK; 1030 } 1031 1032 1033 /** 1034 * Start worker thread for batch processing. 1035 * 1036 * @return #GNUNET_OK on success 1037 */ 1038 static enum GNUNET_GenericReturnValue 1039 start_worker (void) 1040 { 1041 struct Worker *w; 1042 1043 w = GNUNET_new (struct Worker); 1044 sem_init (&w->sem, 1045 0); 1046 if (0 != pthread_create (&w->pt, 1047 NULL, 1048 &worker, 1049 w)) 1050 { 1051 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, 1052 "pthread_create"); 1053 GNUNET_free (w); 1054 return GNUNET_SYSERR; 1055 } 1056 workers++; 1057 return GNUNET_OK; 1058 } 1059 1060 1061 /** 1062 * Stop all worker threads. 1063 */ 1064 static void 1065 stop_workers (void) 1066 { 1067 while (workers > 0) 1068 { 1069 struct Worker *w; 1070 void *result; 1071 1072 sem_down (&worker_sem); 1073 GNUNET_assert (0 == pthread_mutex_lock (&worker_lock)); 1074 w = worker_head; 1075 GNUNET_CONTAINER_DLL_remove (worker_head, 1076 worker_tail, 1077 w); 1078 GNUNET_assert (0 == pthread_mutex_unlock (&worker_lock)); 1079 w->do_shutdown = true; 1080 sem_up (&w->sem); 1081 pthread_join (w->pt, 1082 &result); 1083 GNUNET_assert (result == w); 1084 sem_done (&w->sem); 1085 GNUNET_free (w); 1086 workers--; 1087 } 1088 } 1089 1090 1091 /** 1092 * Initialize key material for denomination key @a dk (also on disk). 1093 * 1094 * @param[in,out] dk denomination key to compute key material for 1095 * @param position where in the DLL will the @a dk go 1096 * @return #GNUNET_OK on success 1097 */ 1098 static enum GNUNET_GenericReturnValue 1099 setup_key (struct DenominationKey *dk, 1100 struct DenominationKey *position) 1101 { 1102 struct Denomination *denom = dk->denom; 1103 struct GNUNET_CRYPTO_CsPrivateKey priv; 1104 struct GNUNET_CRYPTO_CsPublicKey pub; 1105 1106 GNUNET_CRYPTO_cs_private_key_generate (&priv); 1107 GNUNET_CRYPTO_cs_private_key_get_public (&priv, 1108 &pub); 1109 GNUNET_CRYPTO_hash (&pub, 1110 sizeof (pub), 1111 &dk->h_cs.hash); 1112 GNUNET_asprintf ( 1113 &dk->filename, 1114 "%s/%s/%llu-%llu", 1115 keydir, 1116 denom->section, 1117 (unsigned long long) (dk->anchor_start.abs_time.abs_value_us 1118 / GNUNET_TIME_UNIT_SECONDS.rel_value_us 1119 ), 1120 (unsigned long long) (dk->anchor_end.abs_time.abs_value_us 1121 / GNUNET_TIME_UNIT_SECONDS.rel_value_us 1122 )); 1123 if (GNUNET_OK != 1124 GNUNET_DISK_fn_write (dk->filename, 1125 &priv, 1126 sizeof(priv), 1127 GNUNET_DISK_PERM_USER_READ)) 1128 { 1129 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, 1130 "write", 1131 dk->filename); 1132 return GNUNET_SYSERR; 1133 } 1134 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1135 "Setup fresh private key %s at %s in `%s' (generation #%llu)\n", 1136 GNUNET_h2s (&dk->h_cs.hash), 1137 GNUNET_TIME_timestamp2s (dk->anchor_start), 1138 dk->filename, 1139 (unsigned long long) key_gen); 1140 dk->denom_priv = priv; 1141 dk->denom_pub = pub; 1142 dk->key_gen = key_gen; 1143 generate_response (dk); 1144 if (GNUNET_OK != 1145 GNUNET_CONTAINER_multihashmap_put ( 1146 keys, 1147 &dk->h_cs.hash, 1148 dk, 1149 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) 1150 { 1151 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1152 "Duplicate private key created! Terminating.\n"); 1153 GNUNET_free (dk->filename); 1154 GNUNET_free (dk->an); 1155 GNUNET_free (dk); 1156 return GNUNET_SYSERR; 1157 } 1158 GNUNET_CONTAINER_DLL_insert_after (denom->keys_head, 1159 denom->keys_tail, 1160 position, 1161 dk); 1162 return GNUNET_OK; 1163 } 1164 1165 1166 /** 1167 * The withdraw period of a key @a dk has expired. Purge it. 1168 * 1169 * @param[in] dk expired denomination key to purge 1170 */ 1171 static void 1172 purge_key (struct DenominationKey *dk) 1173 { 1174 if (dk->purge) 1175 return; 1176 if (0 != unlink (dk->filename)) 1177 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, 1178 "unlink", 1179 dk->filename); 1180 GNUNET_free (dk->filename); 1181 dk->purge = true; 1182 dk->key_gen = key_gen; 1183 } 1184 1185 1186 /** 1187 * A @a client informs us that a key has been revoked. 1188 * Check if the key is still in use, and if so replace (!) 1189 * it with a fresh key. 1190 * 1191 * @param client the client making the request 1192 * @param rr the revocation request 1193 */ 1194 static enum GNUNET_GenericReturnValue 1195 handle_revoke_request (struct TES_Client *client, 1196 const struct TALER_CRYPTO_CsRevokeRequest *rr) 1197 { 1198 struct DenominationKey *dk; 1199 struct DenominationKey *ndk; 1200 struct Denomination *denom; 1201 1202 (void) client; 1203 GNUNET_assert (0 == pthread_mutex_lock (&keys_lock)); 1204 dk = GNUNET_CONTAINER_multihashmap_get (keys, 1205 &rr->h_cs.hash); 1206 if (NULL == dk) 1207 { 1208 GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); 1209 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 1210 "Revocation request ignored, denomination key %s unknown\n", 1211 GNUNET_h2s (&rr->h_cs.hash)); 1212 return GNUNET_OK; 1213 } 1214 if (dk->purge) 1215 { 1216 GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); 1217 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 1218 "Revocation request ignored, denomination key %s already revoked\n", 1219 GNUNET_h2s (&rr->h_cs.hash)); 1220 return GNUNET_OK; 1221 } 1222 1223 key_gen++; 1224 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1225 "Revoking key %s, bumping generation to %llu\n", 1226 GNUNET_h2s (&rr->h_cs.hash), 1227 (unsigned long long) key_gen); 1228 purge_key (dk); 1229 1230 /* Setup replacement key */ 1231 denom = dk->denom; 1232 ndk = GNUNET_new (struct DenominationKey); 1233 ndk->denom = denom; 1234 ndk->anchor_start = dk->anchor_start; 1235 ndk->anchor_end = dk->anchor_end; 1236 if (GNUNET_OK != 1237 setup_key (ndk, 1238 dk)) 1239 { 1240 GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); 1241 GNUNET_break (0); 1242 GNUNET_SCHEDULER_shutdown (); 1243 globals->global_ret = EXIT_FAILURE; 1244 return GNUNET_SYSERR; 1245 } 1246 GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); 1247 TES_wake_clients (); 1248 return GNUNET_OK; 1249 } 1250 1251 1252 /** 1253 * Handle @a client request @a rdr to create signature. Create the 1254 * signature using the respective key and return the result to 1255 * the client. 1256 * 1257 * @param client the client making the request 1258 * @param rdr the request details 1259 * @return #GNUNET_OK on success 1260 */ 1261 static enum GNUNET_GenericReturnValue 1262 handle_r_derive_request (struct TES_Client *client, 1263 const struct TALER_CRYPTO_CsRDeriveRequest *rdr) 1264 { 1265 struct GNUNET_CRYPTO_CSPublicRPairP r_pub; 1266 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); 1267 enum TALER_ErrorCode ec; 1268 enum GNUNET_GenericReturnValue ret; 1269 1270 ec = do_derive (&rdr->h_cs, 1271 &rdr->nonce, 1272 (0 != ntohl (rdr->for_melt)), 1273 &r_pub); 1274 if (TALER_EC_NONE != ec) 1275 { 1276 return fail_derive (client, 1277 ec); 1278 } 1279 1280 ret = send_derivation (client, 1281 &r_pub); 1282 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1283 "Sent CS Derived R after %s\n", 1284 GNUNET_TIME_relative2s ( 1285 GNUNET_TIME_absolute_get_duration (now), 1286 GNUNET_YES)); 1287 return ret; 1288 } 1289 1290 1291 /** 1292 * Handle @a hdr message received from @a client. 1293 * 1294 * @param client the client that received the message 1295 * @param hdr message that was received 1296 * @return #GNUNET_OK on success 1297 */ 1298 static enum GNUNET_GenericReturnValue 1299 cs_work_dispatch (struct TES_Client *client, 1300 const struct GNUNET_MessageHeader *hdr) 1301 { 1302 uint16_t msize = ntohs (hdr->size); 1303 1304 switch (ntohs (hdr->type)) 1305 { 1306 case TALER_HELPER_CS_MT_REQ_SIGN: 1307 if (msize < sizeof (struct TALER_CRYPTO_CsSignRequestMessage)) 1308 { 1309 GNUNET_break_op (0); 1310 return GNUNET_SYSERR; 1311 } 1312 return handle_sign_request ( 1313 client, 1314 (const struct TALER_CRYPTO_CsSignRequestMessage *) hdr); 1315 case TALER_HELPER_CS_MT_REQ_REVOKE: 1316 if (msize != sizeof (struct TALER_CRYPTO_CsRevokeRequest)) 1317 { 1318 GNUNET_break_op (0); 1319 return GNUNET_SYSERR; 1320 } 1321 return handle_revoke_request ( 1322 client, 1323 (const struct TALER_CRYPTO_CsRevokeRequest *) hdr); 1324 case TALER_HELPER_CS_MT_REQ_BATCH_SIGN: 1325 if (msize <= sizeof (struct TALER_CRYPTO_BatchSignRequest)) 1326 { 1327 GNUNET_break_op (0); 1328 return GNUNET_SYSERR; 1329 } 1330 return handle_batch_sign_request ( 1331 client, 1332 (const struct TALER_CRYPTO_BatchSignRequest *) hdr); 1333 case TALER_HELPER_CS_MT_REQ_BATCH_RDERIVE: 1334 if (msize <= sizeof (struct TALER_CRYPTO_BatchDeriveRequest)) 1335 { 1336 GNUNET_break_op (0); 1337 return GNUNET_SYSERR; 1338 } 1339 return handle_batch_derive_request ( 1340 client, 1341 (const struct TALER_CRYPTO_BatchDeriveRequest *) hdr); 1342 case TALER_HELPER_CS_MT_REQ_RDERIVE: 1343 if (msize != sizeof (struct TALER_CRYPTO_CsRDeriveRequest)) 1344 { 1345 GNUNET_break_op (0); 1346 return GNUNET_SYSERR; 1347 } 1348 return handle_r_derive_request (client, 1349 (const struct 1350 TALER_CRYPTO_CsRDeriveRequest *) hdr); 1351 default: 1352 GNUNET_break_op (0); 1353 return GNUNET_SYSERR; 1354 } 1355 } 1356 1357 1358 /** 1359 * Send our initial key set to @a client together with the 1360 * "sync" terminator. 1361 * 1362 * @param client the client to inform 1363 * @return #GNUNET_OK on success 1364 */ 1365 static enum GNUNET_GenericReturnValue 1366 cs_client_init (struct TES_Client *client) 1367 { 1368 size_t obs = 0; 1369 char *buf; 1370 1371 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1372 "Initializing new client %p\n", 1373 client); 1374 GNUNET_assert (0 == pthread_mutex_lock (&keys_lock)); 1375 for (struct Denomination *denom = denom_head; 1376 NULL != denom; 1377 denom = denom->next) 1378 { 1379 for (struct DenominationKey *dk = denom->keys_head; 1380 NULL != dk; 1381 dk = dk->next) 1382 { 1383 obs += ntohs (dk->an->header.size); 1384 } 1385 } 1386 buf = GNUNET_malloc (obs); 1387 obs = 0; 1388 for (struct Denomination *denom = denom_head; 1389 NULL != denom; 1390 denom = denom->next) 1391 { 1392 for (struct DenominationKey *dk = denom->keys_head; 1393 NULL != dk; 1394 dk = dk->next) 1395 { 1396 GNUNET_memcpy (&buf[obs], 1397 dk->an, 1398 ntohs (dk->an->header.size)); 1399 obs += ntohs (dk->an->header.size); 1400 } 1401 } 1402 client->key_gen = key_gen; 1403 GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); 1404 if (GNUNET_OK != 1405 TES_transmit_raw (client->csock, 1406 obs, 1407 buf)) 1408 { 1409 GNUNET_free (buf); 1410 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1411 "Client %p must have disconnected\n", 1412 client); 1413 return GNUNET_SYSERR; 1414 } 1415 GNUNET_free (buf); 1416 { 1417 struct GNUNET_MessageHeader synced = { 1418 .type = htons (TALER_HELPER_CS_SYNCED), 1419 .size = htons (sizeof (synced)) 1420 }; 1421 1422 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1423 "Sending CS SYNCED message to %p\n", 1424 client); 1425 if (GNUNET_OK != 1426 TES_transmit (client->csock, 1427 &synced)) 1428 { 1429 GNUNET_break (0); 1430 return GNUNET_SYSERR; 1431 } 1432 } 1433 return GNUNET_OK; 1434 } 1435 1436 1437 /** 1438 * Notify @a client about all changes to the keys since 1439 * the last generation known to the @a client. 1440 * 1441 * @param client the client to notify 1442 * @return #GNUNET_OK on success 1443 */ 1444 static enum GNUNET_GenericReturnValue 1445 cs_update_client_keys (struct TES_Client *client) 1446 { 1447 size_t obs = 0; 1448 char *buf; 1449 enum GNUNET_GenericReturnValue ret; 1450 1451 GNUNET_assert (0 == pthread_mutex_lock (&keys_lock)); 1452 for (struct Denomination *denom = denom_head; 1453 NULL != denom; 1454 denom = denom->next) 1455 { 1456 for (struct DenominationKey *key = denom->keys_head; 1457 NULL != key; 1458 key = key->next) 1459 { 1460 if (key->key_gen <= client->key_gen) 1461 continue; 1462 if (key->purge) 1463 obs += sizeof (struct TALER_CRYPTO_CsKeyPurgeNotification); 1464 else 1465 obs += ntohs (key->an->header.size); 1466 } 1467 } 1468 if (0 == obs) 1469 { 1470 /* nothing to do */ 1471 client->key_gen = key_gen; 1472 GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); 1473 return GNUNET_OK; 1474 } 1475 buf = GNUNET_malloc (obs); 1476 obs = 0; 1477 for (struct Denomination *denom = denom_head; 1478 NULL != denom; 1479 denom = denom->next) 1480 { 1481 for (struct DenominationKey *key = denom->keys_head; 1482 NULL != key; 1483 key = key->next) 1484 { 1485 if (key->key_gen <= client->key_gen) 1486 continue; 1487 if (key->purge) 1488 { 1489 struct TALER_CRYPTO_CsKeyPurgeNotification pn = { 1490 .header.type = htons (TALER_HELPER_CS_MT_PURGE), 1491 .header.size = htons (sizeof (pn)), 1492 .h_cs = key->h_cs 1493 }; 1494 1495 GNUNET_memcpy (&buf[obs], 1496 &pn, 1497 sizeof (pn)); 1498 GNUNET_assert (obs + sizeof (pn) 1499 > obs); 1500 obs += sizeof (pn); 1501 } 1502 else 1503 { 1504 GNUNET_memcpy (&buf[obs], 1505 key->an, 1506 ntohs (key->an->header.size)); 1507 GNUNET_assert (obs + ntohs (key->an->header.size) 1508 > obs); 1509 obs += ntohs (key->an->header.size); 1510 } 1511 } 1512 } 1513 client->key_gen = key_gen; 1514 GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); 1515 ret = TES_transmit_raw (client->csock, 1516 obs, 1517 buf); 1518 GNUNET_free (buf); 1519 return ret; 1520 } 1521 1522 1523 /** 1524 * Create a new denomination key (we do not have enough). 1525 * 1526 * @param[in,out] denom denomination key to create 1527 * @param anchor_start when to start key signing validity 1528 * @param anchor_end when to end key signing validity 1529 * @return #GNUNET_OK on success 1530 */ 1531 static enum GNUNET_GenericReturnValue 1532 create_key (struct Denomination *denom, 1533 struct GNUNET_TIME_Timestamp anchor_start, 1534 struct GNUNET_TIME_Timestamp anchor_end) 1535 { 1536 struct DenominationKey *dk; 1537 1538 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1539 "Creating new key for `%s' with start date %s\n", 1540 denom->section, 1541 GNUNET_TIME_timestamp2s (anchor_start)); 1542 dk = GNUNET_new (struct DenominationKey); 1543 dk->denom = denom; 1544 dk->anchor_start = anchor_start; 1545 dk->anchor_end = anchor_end; 1546 if (GNUNET_OK != 1547 setup_key (dk, 1548 denom->keys_tail)) 1549 { 1550 GNUNET_break (0); 1551 GNUNET_free (dk); 1552 GNUNET_SCHEDULER_shutdown (); 1553 globals->global_ret = EXIT_FAILURE; 1554 return GNUNET_SYSERR; 1555 } 1556 return GNUNET_OK; 1557 } 1558 1559 1560 /** 1561 * Obtain the maximum withdraw duration of all denominations. 1562 * 1563 * Must only be called while the #keys_lock is held. 1564 * 1565 * @return maximum withdraw duration, zero if there are no denominations 1566 */ 1567 static struct GNUNET_TIME_Relative 1568 get_maximum_duration (void) 1569 { 1570 struct GNUNET_TIME_Relative ret 1571 = GNUNET_TIME_UNIT_ZERO; 1572 1573 for (struct Denomination *denom = denom_head; 1574 NULL != denom; 1575 denom = denom->next) 1576 { 1577 ret = GNUNET_TIME_relative_max (ret, 1578 denom->duration_withdraw); 1579 } 1580 return ret; 1581 } 1582 1583 1584 /** 1585 * At what time do we need to next create keys if we just did? 1586 * 1587 * @return time when to next create keys if we just finished key generation 1588 */ 1589 static struct GNUNET_TIME_Absolute 1590 action_time (void) 1591 { 1592 struct GNUNET_TIME_Relative md = get_maximum_duration (); 1593 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); 1594 uint64_t mod; 1595 1596 if (GNUNET_TIME_relative_is_zero (md)) 1597 return GNUNET_TIME_UNIT_FOREVER_ABS; 1598 mod = now.abs_value_us % md.rel_value_us; 1599 now.abs_value_us -= mod; 1600 return GNUNET_TIME_absolute_add (now, 1601 md); 1602 } 1603 1604 1605 /** 1606 * Remove all denomination keys of @a denom that have expired. 1607 * 1608 * @param[in,out] denom denomination family to remove keys for 1609 */ 1610 static void 1611 remove_expired_denomination_keys (struct Denomination *denom) 1612 { 1613 while ( (NULL != denom->keys_head) && 1614 GNUNET_TIME_absolute_is_past ( 1615 denom->keys_head->anchor_end.abs_time) ) 1616 { 1617 struct DenominationKey *key = denom->keys_head; 1618 struct DenominationKey *nxt = key->next; 1619 1620 if (0 != key->rc) 1621 break; /* later */ 1622 GNUNET_CONTAINER_DLL_remove (denom->keys_head, 1623 denom->keys_tail, 1624 key); 1625 GNUNET_assert (GNUNET_OK == 1626 GNUNET_CONTAINER_multihashmap_remove ( 1627 keys, 1628 &key->h_cs.hash, 1629 key)); 1630 if ( (! key->purge) && 1631 (0 != unlink (key->filename)) ) 1632 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, 1633 "unlink", 1634 key->filename); 1635 GNUNET_free (key->filename); 1636 GNUNET_free (key->an); 1637 GNUNET_free (key); 1638 key = nxt; 1639 } 1640 } 1641 1642 1643 /** 1644 * Obtain the end anchor to use at this point. Uses the 1645 * #lookahead_sign and then rounds it up by the maximum 1646 * duration of any denomination to arrive at a globally 1647 * valid end-date. 1648 * 1649 * Must only be called while the #keys_lock is held. 1650 * 1651 * @return end anchor 1652 */ 1653 static struct GNUNET_TIME_Timestamp 1654 get_anchor_end (void) 1655 { 1656 struct GNUNET_TIME_Relative md = get_maximum_duration (); 1657 struct GNUNET_TIME_Absolute end 1658 = GNUNET_TIME_relative_to_absolute (lookahead_sign); 1659 uint64_t mod; 1660 1661 if (GNUNET_TIME_relative_is_zero (md)) 1662 return GNUNET_TIME_UNIT_ZERO_TS; 1663 /* Round up 'end' to a multiple of 'md' */ 1664 mod = end.abs_value_us % md.rel_value_us; 1665 end.abs_value_us -= mod; 1666 return GNUNET_TIME_absolute_to_timestamp ( 1667 GNUNET_TIME_absolute_add (end, 1668 md)); 1669 } 1670 1671 1672 /** 1673 * Create all denomination keys that are required for our 1674 * desired lookahead and that we do not yet have. 1675 * 1676 * @param[in,out] opt our options 1677 * @param[in,out] wake set to true if we should wake the clients 1678 */ 1679 static void 1680 create_missing_keys (struct TALER_SECMOD_Options *opt, 1681 bool *wake) 1682 { 1683 struct GNUNET_TIME_Timestamp start; 1684 struct GNUNET_TIME_Timestamp end; 1685 1686 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1687 "Updating denominations ...\n"); 1688 start = opt->global_now; 1689 GNUNET_assert (0 == pthread_mutex_lock (&keys_lock)); 1690 end = get_anchor_end (); 1691 for (struct Denomination *denom = denom_head; 1692 NULL != denom; 1693 denom = denom->next) 1694 { 1695 struct GNUNET_TIME_Timestamp anchor_start; 1696 struct GNUNET_TIME_Timestamp anchor_end; 1697 struct GNUNET_TIME_Timestamp next_end; 1698 bool finished = false; 1699 1700 remove_expired_denomination_keys (denom); 1701 if (NULL != denom->keys_tail) 1702 { 1703 anchor_start = denom->keys_tail->anchor_end; 1704 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1705 "Expanding keys of denomination `%s', last key %s valid for another %s\n", 1706 denom->section, 1707 GNUNET_h2s (&denom->keys_tail->h_cs.hash), 1708 GNUNET_TIME_relative2s ( 1709 GNUNET_TIME_absolute_get_remaining ( 1710 anchor_start.abs_time), 1711 true)); 1712 } 1713 else 1714 { 1715 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1716 "Starting keys of denomination `%s'\n", 1717 denom->section); 1718 anchor_start = start; 1719 } 1720 finished = GNUNET_TIME_timestamp_cmp (anchor_start, 1721 >=, 1722 end); 1723 while (! finished) 1724 { 1725 anchor_end = GNUNET_TIME_absolute_to_timestamp ( 1726 GNUNET_TIME_absolute_add (anchor_start.abs_time, 1727 denom->duration_withdraw)); 1728 next_end = GNUNET_TIME_absolute_to_timestamp ( 1729 GNUNET_TIME_absolute_add (anchor_end.abs_time, 1730 denom->duration_withdraw)); 1731 if (GNUNET_TIME_timestamp_cmp (next_end, 1732 >, 1733 end)) 1734 { 1735 anchor_end = end; /* extend period to align end periods */ 1736 finished = true; 1737 } 1738 /* adjust start time down to ensure overlap */ 1739 anchor_start = GNUNET_TIME_absolute_to_timestamp ( 1740 GNUNET_TIME_absolute_subtract (anchor_start.abs_time, 1741 overlap_duration)); 1742 if (! *wake) 1743 { 1744 key_gen++; 1745 *wake = true; 1746 } 1747 if (GNUNET_OK != 1748 create_key (denom, 1749 anchor_start, 1750 anchor_end)) 1751 { 1752 GNUNET_break (0); 1753 return; 1754 } 1755 anchor_start = anchor_end; 1756 } 1757 remove_expired_denomination_keys (denom); 1758 } 1759 GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); 1760 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1761 "Updating denominations finished ...\n"); 1762 } 1763 1764 1765 /** 1766 * Task run periodically to expire keys and/or generate fresh ones. 1767 * 1768 * @param cls the `struct TALER_SECMOD_Options *` 1769 */ 1770 static void 1771 update_denominations (void *cls) 1772 { 1773 struct TALER_SECMOD_Options *opt = cls; 1774 struct GNUNET_TIME_Absolute at; 1775 bool wake = false; 1776 1777 (void) cls; 1778 keygen_task = NULL; 1779 opt->global_now = GNUNET_TIME_timestamp_get (); 1780 create_missing_keys (opt, 1781 &wake); 1782 if (wake) 1783 TES_wake_clients (); 1784 at = action_time (); 1785 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1786 "Next key generation due at %s\n", 1787 GNUNET_TIME_absolute2s (at)); 1788 keygen_task = GNUNET_SCHEDULER_add_at (at, 1789 &update_denominations, 1790 opt); 1791 } 1792 1793 1794 /** 1795 * Parse private key of denomination @a denom in @a buf. 1796 * 1797 * @param[out] denom denomination of the key 1798 * @param filename name of the file we are parsing, for logging 1799 * @param priv key material 1800 */ 1801 static void 1802 parse_key (struct Denomination *denom, 1803 const char *filename, 1804 const struct GNUNET_CRYPTO_CsPrivateKey *priv) 1805 { 1806 char *anchor_s; 1807 char dummy; 1808 unsigned long long anchor_start_ll; 1809 unsigned long long anchor_end_ll; 1810 struct GNUNET_TIME_Timestamp anchor_start; 1811 struct GNUNET_TIME_Timestamp anchor_end; 1812 char *nf = NULL; 1813 1814 anchor_s = strrchr (filename, 1815 '/'); 1816 if (NULL == anchor_s) 1817 { 1818 /* File in a directory without '/' in the name, this makes no sense. */ 1819 GNUNET_break (0); 1820 return; 1821 } 1822 anchor_s++; 1823 if (2 != sscanf (anchor_s, 1824 "%llu-%llu%c", 1825 &anchor_start_ll, 1826 &anchor_end_ll, 1827 &dummy)) 1828 { 1829 /* try legacy mode */ 1830 if (1 != sscanf (anchor_s, 1831 "%llu%c", 1832 &anchor_start_ll, 1833 &dummy)) 1834 { 1835 /* Filenames in KEYDIR must ONLY be the anchor time in seconds! */ 1836 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 1837 "Filename `%s' invalid for key file, skipping\n", 1838 anchor_s); 1839 return; 1840 } 1841 anchor_start.abs_time.abs_value_us 1842 = anchor_start_ll * GNUNET_TIME_UNIT_SECONDS.rel_value_us; 1843 if (anchor_start_ll != anchor_start.abs_time.abs_value_us 1844 / GNUNET_TIME_UNIT_SECONDS.rel_value_us) 1845 { 1846 /* Integer overflow. Bad, invalid filename. */ 1847 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 1848 "Integer overflow. Filename `%s' invalid for key file, skipping\n", 1849 anchor_s); 1850 return; 1851 } 1852 anchor_end 1853 = GNUNET_TIME_absolute_to_timestamp ( 1854 GNUNET_TIME_absolute_add (anchor_start.abs_time, 1855 denom->duration_withdraw)); 1856 GNUNET_asprintf ( 1857 &nf, 1858 "%s/%s/%llu-%llu", 1859 keydir, 1860 denom->section, 1861 anchor_start_ll, 1862 (unsigned long long) (anchor_end.abs_time.abs_value_us 1863 / GNUNET_TIME_UNIT_SECONDS.rel_value_us)); 1864 /* Try to fix the legacy filename */ 1865 if (0 != 1866 rename (filename, 1867 nf)) 1868 { 1869 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, 1870 "rename", 1871 filename); 1872 GNUNET_free (nf); 1873 } 1874 } 1875 else 1876 { 1877 anchor_start.abs_time.abs_value_us 1878 = anchor_start_ll * GNUNET_TIME_UNIT_SECONDS.rel_value_us; 1879 anchor_end.abs_time.abs_value_us 1880 = anchor_end_ll * GNUNET_TIME_UNIT_SECONDS.rel_value_us; 1881 if ( (anchor_start_ll != anchor_start.abs_time.abs_value_us 1882 / GNUNET_TIME_UNIT_SECONDS.rel_value_us) || 1883 (anchor_end_ll != anchor_end.abs_time.abs_value_us 1884 / GNUNET_TIME_UNIT_SECONDS.rel_value_us) ) 1885 { 1886 /* Integer overflow. Bad, invalid filename. */ 1887 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 1888 "Integer overflow. Filename `%s' invalid for key file, skipping\n", 1889 anchor_s); 1890 return; 1891 } 1892 } 1893 1894 { 1895 struct DenominationKey *dk; 1896 struct DenominationKey *before; 1897 1898 dk = GNUNET_new (struct DenominationKey); 1899 dk->denom_priv = *priv; 1900 dk->denom = denom; 1901 dk->anchor_start = anchor_start; 1902 dk->anchor_end = anchor_end; 1903 dk->filename = (NULL == nf) ? GNUNET_strdup (filename) : nf; 1904 GNUNET_CRYPTO_cs_private_key_get_public (priv, 1905 &dk->denom_pub); 1906 GNUNET_CRYPTO_hash (&dk->denom_pub, 1907 sizeof (dk->denom_pub), 1908 &dk->h_cs.hash); 1909 generate_response (dk); 1910 if (GNUNET_OK != 1911 GNUNET_CONTAINER_multihashmap_put ( 1912 keys, 1913 &dk->h_cs.hash, 1914 dk, 1915 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) 1916 { 1917 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1918 "Duplicate private key %s detected in file `%s'. Skipping.\n", 1919 GNUNET_h2s (&dk->h_cs.hash), 1920 filename); 1921 GNUNET_free (dk->an); 1922 GNUNET_free (dk); 1923 return; 1924 } 1925 before = NULL; 1926 for (struct DenominationKey *pos = denom->keys_head; 1927 NULL != pos; 1928 pos = pos->next) 1929 { 1930 if (GNUNET_TIME_timestamp_cmp (pos->anchor_start, 1931 >, 1932 anchor_start)) 1933 break; 1934 before = pos; 1935 } 1936 GNUNET_CONTAINER_DLL_insert_after (denom->keys_head, 1937 denom->keys_tail, 1938 before, 1939 dk); 1940 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1941 "Imported key %s from `%s'\n", 1942 GNUNET_h2s (&dk->h_cs.hash), 1943 filename); 1944 } 1945 } 1946 1947 1948 /** 1949 * Import a private key from @a filename for the denomination 1950 * given in @a cls. 1951 * 1952 * @param[in,out] cls a `struct Denomiantion` 1953 * @param filename name of a file in the directory 1954 * @return #GNUNET_OK (always, continue to iterate) 1955 */ 1956 static enum GNUNET_GenericReturnValue 1957 import_key (void *cls, 1958 const char *filename) 1959 { 1960 struct Denomination *denom = cls; 1961 struct GNUNET_DISK_FileHandle *fh; 1962 struct GNUNET_DISK_MapHandle *map; 1963 void *ptr; 1964 int fd; 1965 struct stat sbuf; 1966 1967 { 1968 struct stat lsbuf; 1969 1970 if (0 != lstat (filename, 1971 &lsbuf)) 1972 { 1973 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, 1974 "lstat", 1975 filename); 1976 return GNUNET_OK; 1977 } 1978 if (! S_ISREG (lsbuf.st_mode)) 1979 { 1980 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1981 "File `%s' is not a regular file, which is not allowed for private keys!\n", 1982 filename); 1983 return GNUNET_OK; 1984 } 1985 } 1986 1987 fd = open (filename, 1988 O_RDONLY | O_CLOEXEC); 1989 if (-1 == fd) 1990 { 1991 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, 1992 "open", 1993 filename); 1994 return GNUNET_OK; 1995 } 1996 if (0 != fstat (fd, 1997 &sbuf)) 1998 { 1999 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, 2000 "stat", 2001 filename); 2002 GNUNET_break (0 == close (fd)); 2003 return GNUNET_OK; 2004 } 2005 if (! S_ISREG (sbuf.st_mode)) 2006 { 2007 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 2008 "File `%s' is not a regular file, which is not allowed for private keys!\n", 2009 filename); 2010 GNUNET_break (0 == close (fd)); 2011 return GNUNET_OK; 2012 } 2013 if (0 != (sbuf.st_mode & (S_IWUSR | S_IRWXG | S_IRWXO))) 2014 { 2015 /* permission are NOT tight, try to patch them up! */ 2016 if (0 != 2017 fchmod (fd, 2018 S_IRUSR)) 2019 { 2020 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, 2021 "fchmod", 2022 filename); 2023 /* refuse to use key if file has wrong permissions */ 2024 GNUNET_break (0 == close (fd)); 2025 return GNUNET_OK; 2026 } 2027 } 2028 fh = GNUNET_DISK_get_handle_from_int_fd (fd); 2029 if (NULL == fh) 2030 { 2031 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, 2032 "open", 2033 filename); 2034 GNUNET_break (0 == close (fd)); 2035 return GNUNET_OK; 2036 } 2037 if (sbuf.st_size != sizeof(struct GNUNET_CRYPTO_CsPrivateKey)) 2038 { 2039 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 2040 "File `%s' too big to be a private key\n", 2041 filename); 2042 GNUNET_DISK_file_close (fh); 2043 return GNUNET_OK; 2044 } 2045 ptr = GNUNET_DISK_file_map (fh, 2046 &map, 2047 GNUNET_DISK_MAP_TYPE_READ, 2048 (size_t) sbuf.st_size); 2049 if (NULL == ptr) 2050 { 2051 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, 2052 "mmap", 2053 filename); 2054 GNUNET_DISK_file_close (fh); 2055 return GNUNET_OK; 2056 } 2057 parse_key (denom, 2058 filename, 2059 (const struct GNUNET_CRYPTO_CsPrivateKey *) ptr); 2060 GNUNET_DISK_file_unmap (map); 2061 GNUNET_DISK_file_close (fh); 2062 return GNUNET_OK; 2063 } 2064 2065 2066 /** 2067 * Parse configuration for denomination type parameters. Also determines 2068 * our anchor by looking at the existing denominations of the same type. 2069 * 2070 * @param cfg configuration to use 2071 * @param ct section in the configuration file giving the denomination type parameters 2072 * @param[out] denom set to the denomination parameters from the configuration 2073 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the configuration is invalid 2074 */ 2075 static enum GNUNET_GenericReturnValue 2076 parse_denomination_cfg (const struct GNUNET_CONFIGURATION_Handle *cfg, 2077 const char *ct, 2078 struct Denomination *denom) 2079 { 2080 char *secname; 2081 2082 GNUNET_asprintf (&secname, 2083 "%s-secmod-cs", 2084 globals->section); 2085 if (GNUNET_OK != 2086 GNUNET_CONFIGURATION_get_value_time (cfg, 2087 ct, 2088 "DURATION_WITHDRAW", 2089 &denom->duration_withdraw)) 2090 { 2091 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 2092 ct, 2093 "DURATION_WITHDRAW"); 2094 GNUNET_free (secname); 2095 return GNUNET_SYSERR; 2096 } 2097 if (GNUNET_TIME_relative_cmp (denom->duration_withdraw, 2098 <, 2099 GNUNET_TIME_UNIT_SECONDS)) 2100 { 2101 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, 2102 ct, 2103 "DURATION_WITHDRAW", 2104 "less than one second is not supported"); 2105 GNUNET_free (secname); 2106 return GNUNET_SYSERR; 2107 } 2108 if (GNUNET_TIME_relative_cmp (overlap_duration, 2109 >=, 2110 denom->duration_withdraw)) 2111 { 2112 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, 2113 secname, 2114 "OVERLAP_DURATION", 2115 "Value given must be smaller than value for DURATION_WITHDRAW!"); 2116 GNUNET_free (secname); 2117 return GNUNET_SYSERR; 2118 } 2119 GNUNET_free (secname); 2120 denom->section = GNUNET_strdup (ct); 2121 return GNUNET_OK; 2122 } 2123 2124 2125 /** 2126 * Closure for #load_denominations. 2127 */ 2128 struct LoadContext 2129 { 2130 2131 /** 2132 * Configuration to use. 2133 */ 2134 const struct GNUNET_CONFIGURATION_Handle *cfg; 2135 2136 /** 2137 * Current time to use. 2138 */ 2139 struct GNUNET_TIME_Timestamp t; 2140 2141 /** 2142 * Status, to be set to #GNUNET_SYSERR on failure 2143 */ 2144 enum GNUNET_GenericReturnValue ret; 2145 }; 2146 2147 2148 /** 2149 * Generate new denomination signing keys for the denomination type of the given @a 2150 * denomination_alias. 2151 * 2152 * @param cls a `struct LoadContext`, with 'ret' to be set to #GNUNET_SYSERR on failure 2153 * @param denomination_alias name of the denomination's section in the configuration 2154 */ 2155 static void 2156 load_denominations (void *cls, 2157 const char *denomination_alias) 2158 { 2159 struct LoadContext *ctx = cls; 2160 struct Denomination *denom; 2161 char *cipher; 2162 2163 if ( (0 != strncasecmp (denomination_alias, 2164 "coin_", 2165 strlen ("coin_"))) && 2166 (0 != strncasecmp (denomination_alias, 2167 "coin-", 2168 strlen ("coin-"))) ) 2169 return; /* not a denomination type definition */ 2170 if (GNUNET_OK != 2171 GNUNET_CONFIGURATION_get_value_string (ctx->cfg, 2172 denomination_alias, 2173 "CIPHER", 2174 &cipher)) 2175 { 2176 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 2177 denomination_alias, 2178 "CIPHER"); 2179 return; 2180 } 2181 if (0 != strcmp (cipher, "CS")) 2182 { 2183 GNUNET_free (cipher); 2184 return; /* Ignore denominations of other types than CS*/ 2185 } 2186 GNUNET_free (cipher); 2187 2188 denom = GNUNET_new (struct Denomination); 2189 if (GNUNET_OK != 2190 parse_denomination_cfg (ctx->cfg, 2191 denomination_alias, 2192 denom)) 2193 { 2194 ctx->ret = GNUNET_SYSERR; 2195 GNUNET_free (denom); 2196 return; 2197 } 2198 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 2199 "Loading keys for denomination %s\n", 2200 denom->section); 2201 { 2202 char *dname; 2203 2204 GNUNET_asprintf (&dname, 2205 "%s/%s", 2206 keydir, 2207 denom->section); 2208 GNUNET_break (GNUNET_OK == 2209 GNUNET_DISK_directory_create (dname)); 2210 GNUNET_DISK_directory_scan (dname, 2211 &import_key, 2212 denom); 2213 GNUNET_free (dname); 2214 } 2215 GNUNET_CONTAINER_DLL_insert (denom_head, 2216 denom_tail, 2217 denom); 2218 } 2219 2220 2221 /** 2222 * Load the various duration values from @a cfg 2223 * 2224 * @param cfg configuration to use 2225 * @return #GNUNET_OK on success 2226 */ 2227 static enum GNUNET_GenericReturnValue 2228 load_durations (const struct GNUNET_CONFIGURATION_Handle *cfg) 2229 { 2230 char *secname; 2231 2232 GNUNET_asprintf (&secname, 2233 "%s-secmod-cs", 2234 globals->section); 2235 if (GNUNET_OK != 2236 GNUNET_CONFIGURATION_get_value_time (cfg, 2237 secname, 2238 "OVERLAP_DURATION", 2239 &overlap_duration)) 2240 { 2241 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 2242 secname, 2243 "OVERLAP_DURATION"); 2244 GNUNET_free (secname); 2245 return GNUNET_SYSERR; 2246 } 2247 if (GNUNET_OK != 2248 GNUNET_CONFIGURATION_get_value_time (cfg, 2249 secname, 2250 "LOOKAHEAD_SIGN", 2251 &lookahead_sign)) 2252 { 2253 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 2254 secname, 2255 "LOOKAHEAD_SIGN"); 2256 GNUNET_free (secname); 2257 return GNUNET_SYSERR; 2258 } 2259 GNUNET_free (secname); 2260 return GNUNET_OK; 2261 } 2262 2263 2264 /** 2265 * Function run on shutdown. Stops the various jobs (nicely). 2266 * 2267 * @param cls a `struct TALER_SECMOD_Options` 2268 */ 2269 static void 2270 do_shutdown (void *cls) 2271 { 2272 (void) cls; 2273 TES_listen_stop (); 2274 if (NULL != keygen_task) 2275 { 2276 GNUNET_SCHEDULER_cancel (keygen_task); 2277 keygen_task = NULL; 2278 } 2279 stop_workers (); 2280 sem_done (&worker_sem); 2281 } 2282 2283 2284 void 2285 TALER_SECMOD_cs_run (void *cls, 2286 char *const *args, 2287 const char *cfgfile, 2288 const struct GNUNET_CONFIGURATION_Handle *cfg) 2289 { 2290 static struct TES_Callbacks cb = { 2291 .dispatch = &cs_work_dispatch, 2292 .updater = &cs_update_client_keys, 2293 .init = &cs_client_init 2294 }; 2295 struct TALER_SECMOD_Options *opt = cls; 2296 char *secname; 2297 2298 (void) args; 2299 (void) cfgfile; 2300 globals = opt; 2301 if (GNUNET_TIME_timestamp_cmp (opt->global_now, 2302 !=, 2303 opt->global_now_tmp)) 2304 { 2305 /* The user gave "--now", use it! */ 2306 opt->global_now = opt->global_now_tmp; 2307 } 2308 else 2309 { 2310 /* get current time again, we may be timetraveling! */ 2311 opt->global_now = GNUNET_TIME_timestamp_get (); 2312 } 2313 GNUNET_asprintf (&secname, 2314 "%s-secmod-cs", 2315 opt->section); 2316 if (GNUNET_OK != 2317 GNUNET_CONFIGURATION_get_value_filename (cfg, 2318 secname, 2319 "KEY_DIR", 2320 &keydir)) 2321 { 2322 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 2323 secname, 2324 "KEY_DIR"); 2325 GNUNET_free (secname); 2326 opt->global_ret = EXIT_NOTCONFIGURED; 2327 return; 2328 } 2329 if (GNUNET_OK != 2330 load_durations (cfg)) 2331 { 2332 opt->global_ret = EXIT_NOTCONFIGURED; 2333 GNUNET_free (secname); 2334 return; 2335 } 2336 opt->global_ret = TES_listen_start (cfg, 2337 secname, 2338 &cb); 2339 GNUNET_free (secname); 2340 if (0 != opt->global_ret) 2341 return; 2342 sem_init (&worker_sem, 2343 0); 2344 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, 2345 opt); 2346 if (0 == opt->max_workers) 2347 { 2348 long lret; 2349 2350 lret = sysconf (_SC_NPROCESSORS_CONF); 2351 if (lret <= 0) 2352 lret = 1; 2353 opt->max_workers = (unsigned int) lret; 2354 } 2355 for (unsigned int i = 0; i<opt->max_workers; i++) 2356 if (GNUNET_OK != 2357 start_worker ()) 2358 { 2359 GNUNET_SCHEDULER_shutdown (); 2360 return; 2361 } 2362 /* Load denominations */ 2363 keys = GNUNET_CONTAINER_multihashmap_create (65536, 2364 true); 2365 { 2366 struct LoadContext lc = { 2367 .cfg = cfg, 2368 .ret = GNUNET_OK, 2369 .t = opt->global_now 2370 }; 2371 bool wake = true; 2372 2373 GNUNET_assert (0 == pthread_mutex_lock (&keys_lock)); 2374 GNUNET_CONFIGURATION_iterate_sections (cfg, 2375 &load_denominations, 2376 &lc); 2377 GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); 2378 if (GNUNET_OK != lc.ret) 2379 { 2380 opt->global_ret = EXIT_FAILURE; 2381 GNUNET_SCHEDULER_shutdown (); 2382 return; 2383 } 2384 create_missing_keys (opt, 2385 &wake); 2386 } 2387 if (NULL == denom_head) 2388 { 2389 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 2390 "No CS denominations configured. Make sure section names start with `%s' if you are using CS!\n", 2391 opt->section); 2392 TES_wake_clients (); 2393 return; 2394 } 2395 /* start job to keep keys up-to-date; MUST be run before the #listen_task, 2396 hence with priority. */ 2397 keygen_task = GNUNET_SCHEDULER_add_with_priority ( 2398 GNUNET_SCHEDULER_PRIORITY_URGENT, 2399 &update_denominations, 2400 opt); 2401 }