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