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